robsonkades/agent-skills/java-application-security-basics
- community
Checking that the SKILL.md file is still in the repository.
Application-security judgement for Java 21+: password storage with current memory-hard KDF parameters, constant-time verification, secure randomness, authorisation inside the protected operation, adversarial validation, reversible-cryptography boundaries, and secret-safe types. Use when credentials, password hashes, salts, bearer tokens or peppers change; when MessageDigest, SecureRandom, Random, UUID, Cipher, Mac or PasswordEncoder serves a security purpose; when a controller annotation is the only authorisation check; when identity comes from the request instead of the principal; or when a generic CryptoUtils wrapper is proposed. Code-level only: layered validation is java-defensive-programming, redaction is structured-logging, ReDoS is java-strings-and-text, and deserialisation is java-serialization-hardening.
Install
npx vskill@latest install robsonkades/agent-skills/java-application-security-basicsSKILL.md
Java Application Security Basics
Purpose
The code-level half of application security — the decisions that survive replacing the security framework. It prevents two failures: "I used the framework default" mistaken for "I followed current guidance", and authorisation that lives only at the HTTP entry point.
Scope
Covers: password storage and verification, secure randomness, authorisation as a precondition of the protected operation, the adversarial half of input validation, secrets in source and in types, and safe review boundaries for reversible cryptography.
Does not cover: transport security, nor framework configuration — filter chains, JWT and OAuth2 resource server, method-security wiring and CORS belong to spring-security-for-apis, available separately in this catalog. Nor does it apply to a service with no credential store, no untrusted input and no per-instance ownership rule: threading an Actor through that domain is cost, no benefit.
For a handoff, pass the resolved Java/framework versions, reachable entry paths, required policy and observed evidence; ask the owning specialist for the applicable configuration or validation result. If unavailable, retain the code-level findings and state what remains unverified; an untested framework annotation is not proof that a guard executes.
Workflow
Before recommending APIs or parameters, inspect the project's compiler release/toolchain, resolved security-library versions, runtime image, credential format and binding standard. Java 21 is this skill's example baseline, not permission to upgrade the target or add Spring or BouncyCastle. Version-specific facts below are dated examples; verify them against the resolved version. If evidence is missing, state the gap and keep the proposed change conditional. Respect the requested mode: report findings for a review, and implement scoped code corrections when authorized. Use synthetic credentials and isolated fixtures for adversarial checks; finding a possible live secret does not authorize using it, contacting its service or rotating it.
- Name the asset and the reachable attacker. "A leaked database backup" and "another
tenant's authenticated user" lead to different code; "make it more secure" leads to none.
- Read the KDF parameters, not the class name. Some Spring Security defaults sit below
current OWASP guidance, so "I used PasswordEncoderFactories" is not a compliance claim:
| Spring Security 7.1 default | OWASP (fetched 2026-08-27) | ||
|---|---|---|---|
| Argon2id | m=16384 KiB, t=2, p=1 (defaultsForSpringSecurity_v5_8) | m=19456 KiB at t=2, p=1 | |
| PBKDF2-HMAC-SHA256 | 310,000 iterations | 600,000 iterations | |
| bcrypt | strength 10 | 10 is the stated _minimum_ |
DelegatingPasswordEncoder.idForEncode is still "bcrypt" in 7.1.1, not Argon2id — so it does not select OWASP's first choice for new storage. bcrypt strength 10 meets its minimum; adequacy still depends on measured cost and the binding standard. new Argon2PasswordEncoder(16, 32, 1, 19456, 2) closes the Argon2 parameter gap.
- Make authorisation a precondition of the protected operation. Use the domain operation
for an instance rule, or retain an application-service guard when every relevant entry path necessarily passes it and its checked state stays consistent with the write. An Actor parameter is an obligation, not proof of identity: construct stable claims only from a trusted authentication context, and do not let request JSON supply roles or tenant. Keep the controller annotation as cheap early rejection; it stops being the only check. Authorise the _instance_: "has role CUSTOMER" without "and this order is theirs".
- Allowlist attacker-controlled input as structure, but it is not the control — regex over
hostile input is a DoS vector (java-strings-and-text); hostile bytes are java-serialization-hardening.
- Trace every secret from where it enters to everywhere it can be rendered — source,
config, toString(), equals, an exception message, an HTTP error body. Redaction at the log encoder is structured-logging's backstop; keeping it out of the type is the control.
- Verify against
references/review.md— a rule you cannot check on a diff is no rule.
Decision rules
Rules
- Password length policy conflicts between the two standards teams cite, so say which one binds
instead of picking silently: NIST SP 800-63B-4 (July 2025) makes 15 characters a SHALL where the password is the _single_ factor (8 within MFA); ASVS 5.0 §6.2.1 sets the floor at 8, 15 recommended. The deciding question is not which is stricter but _which regime does this system answer to, and is the password ever the only factor?_ Both forbid composition rules and periodic rotation regardless — and never write that "NIST relaxed the password rules": it dropped composition and expiry and raised the single-factor floor. Requirement text and the three questions that settle it: references/password-policy.md.
- Spring bcrypt's 72-byte ceiling differs between writing and verification: the
CVE-2025-22228 fix (6.3.8 / 6.4.4, March 2025) makes encode throw above it. In the named 7.1.1 implementation, matches still skips the guard, including for a newly written hash of a 72-byte password plus an over-length candidate suffix. An uncaught re-encode can fail registration, change-password or rehash-on-login. Enforce the byte limit consistently or migrate to a suitable KDF without truncation; plan recovery for existing over-length users.
- Make account-existence paths observationally similar: the same external response, one KDF
on both paths, and shared throttling. This mitigates rather than proves indistinguishability: caches, database work, network jitter and downstream side effects remain measurable. orElseThrow() before comparison — or distinct not-found/not-permitted errors — is an enumeration oracle.
- Treat authorisation and mutation as one consistency decision. A check against an object read
in one transaction followed by an unconditional write in another is a TOCTOU bug; use a transaction with the required isolation, a version/CAS predicate, or a conditional update that includes tenant/owner and expected state. Returning 404 for both absent and forbidden resources hides detail from the caller but is not the authorisation control.
- Password-reset and API-key flows are credential systems, not random-string helpers. Generate
at least the entropy required by the applicable standard, display the raw value once and enforce purpose/subject/expiry. A domain-separated digest can protect a high-entropy random token at rest; a six-digit code has only one million possibilities, so hashing it does not provide comparable offline-guessing resistance. Short codes need an explicit attempt budget, short validity and a reviewed verification/storage policy (references/password-storage.md §5). Atomically consume reset tokens; enforce revocation and rotation for reusable API keys. Rate-limit redemption; do not log query strings containing bearer material.
- Hash what only needs equality verification; encrypt only what the application must recover.
With reversible data, Cipher.getInstance("AES") delegates mode and padding to the provider. Prefer a platform/KMS envelope or a reviewed AES/GCM/NoPadding/ChaCha20-Poly1305 facility; authenticate tenant, record id, schema and key version as AAD where those fields must not be swappable. Nonce uniqueness is per key, and decrypt must release no plaintext before tag verification. Store algorithm, key version, nonce and ciphertext/tag so rotation is possible; never store a plaintext data-encryption key beside the ciphertext it protects. An encrypted (wrapped) data key may accompany the ciphertext when its wrapping key is separately protected. Check the consuming API too: both CipherInputStream and CipherOutputStream can conceal integrity-check failures during decryption under their documented contracts. A successful close() or an empty result is not proof of authentication. Use direct Cipher authentication completion or a vetted AEAD facility. Test legitimate inputs, including empty plaintext when the application allows it, and reject tampered ciphertext, tag, AAD and wrong-key cases without publishing output or a success effect.
- A secret in an automatically generated record or Lombok
@DatatoString()can leak
through log.info("processing {}", request); check custom exclusions and renderers too.
- Two moves make code worse. Encrypting what only needs hashing ("so we can support
password recovery") trades away the property that mattered — a dump yields no passwords — for a feature that is itself a defect, and adds a key needing rotation and custody. The custom crypto wrapper that loses the credential contract: discarding algorithm/parameter metadata or replacing a vetted verifier destroys migration and reviewability. Inspect the implementation; hash(String) alone proves neither defect. A small policy adapter can be adequate when it preserves versioned encodings, verification and upgrade behavior.
Failure modes and production evidence
This is the start of the file. Read the full SKILL.md on GitHub.
Security
- Security scanPassed, 95 of 100Pattern checks on the skill's files.
- Model reviewPassed
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingskills/java-application-security-basics/SKILL.md
Popularity
- Repository stars
- 2
- 7-day trend score
- 8
Stars and forks are for the whole GitHub repository, not this skill alone. Refreshed 2 Oct 2026, 22 days ago.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/robsonkades/agent-skills/java-application-security-basics)