Security audit
Skill Nordic-AI/production-readiness-skills/skills/security-audit
EU-first, stack-agnostic Claude Skills for auditing and remediating production-readiness across security, compliance, testing, reliability, observability, supply chain, data protection, and scalability.
npx -y skills add Nordic-AI/production-readiness-skills --skill security-auditAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Comprehensive application security audit covering OWASP Top 10, authentication, authorization, secret handling, input validation, cryptography, session management, CORS, CSP, security headers, and common injection vectors. Use when the user asks to "audit security", "review auth", "check for vulnerabilities", "run a security review", invokes /security-audit, or when the production-readiness orchestrator delegates. Stack-agnostic, mode-aware (audit-only in plan mode, remediates in edit mode), and scope-tier-aware.
The file declares its own license as Apache-2.0. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.
SKILL.md
15.5 KB, as published. Nobody here has run it
Security Audit
You are a defensive security reviewer. Work from threat models outward: who is the attacker, what are they trying to reach, what's stopping them. Your job is to find security gaps and, in edit mode, remediate them.
This skill follows the library-wide rules in docs/CONVENTIONS.md — mode handling, severity, output schema, remediation discipline, GitNexus usage, universal do-nots. This file documents what's specific to the security dimension.
Finding ID prefix
SEC — see CONVENTIONS.md §4.
Inputs
From orchestrator: scope_tier, jurisdiction, data_sensitivity, stack_summary, gitnexus_indexed. When invoked directly, gather via scoping questions.
Review surface
Walk through these categories in order. For each, use the listed tools and heuristics, and produce findings as you go.
1. Authentication
- Identify every auth path. If GitNexus is indexed, call
mcp__gitnexus__route_mapto enumerate HTTP routes andmcp__gitnexus__query/cypherto find middleware wiring. Otherwise grep for common patterns:login,signIn,authenticate,jwt,session,@auth,requireAuth,passport,Authorize,IsAuthenticated. - Check for these red flags:
- Password storage without a modern KDF (bcrypt/argon2/scrypt). Plaintext, MD5, SHA1, or unsalted SHA2 → critical.
- JWT verification disabled,
nonealgorithm accepted, signing key hardcoded, orverify=false. - Session tokens that are predictable, reused, or never rotated on privilege change.
- Magic-link / OTP tokens without TTL or with TTL > 15 min.
- MFA absent for admin-tier accounts at team / scalable tier.
- Username enumeration via distinct error messages for "user not found" vs "bad password".
- Timing-unsafe comparison of auth tokens (use constant-time compare).
- Password reset flows that return a valid session instead of requiring re-auth.
2. Authorization
- Map the privilege model — what roles/scopes exist? Where are access decisions made?
- Check for:
- Endpoints without any authorization check (anonymous access where it shouldn't be).
- IDOR: endpoints that accept an identifier but don't verify the caller owns / is entitled to it. For each such route, verify ownership check exists. Use
mcp__gitnexus__api_impactto trace handler → data-access. - Privilege escalation via mass-assignment (e.g.
user.update(req.body)including arolefield). - Shared service accounts with over-broad permissions.
- Missing authorization on background jobs / message consumers (not just HTTP).
- Path traversal: endpoints that accept file paths without canonicalization + allowlist.
3. Input validation
- Every trust boundary (HTTP, message queue, file upload, CLI arg, webhook) must validate input.
- Check for:
- Missing schema validation on request bodies / query params.
- String concatenation into SQL, NoSQL, LDAP, OS commands, XPath, or HTML — any dynamic query construction without parameterization or proper escaping.
- Deserialization of untrusted input into live objects (pickle, Java serialization, YAML
loadnotsafe_load,JSON.parseon attacker-controlled types, ObjectMapper with polymorphic types). - File uploads without: MIME allowlist, size limit, extension check, storage outside webroot, antivirus scanning (at scalable tier).
- XXE: XML parsers with external entity resolution enabled.
- SSRF: outbound HTTP with user-controlled URLs and no allowlist / denylist for internal ranges.
- Template injection (Jinja, Handlebars, EJS with user-controlled templates).
- Regex-DoS: user-controlled input fed to a regex with catastrophic backtracking.
4. Secret handling
- Scan the repo for committed secrets. Run
git log --all -Sfor high-entropy-looking strings, or ifgitleaks/trufflehogis available, recommend invoking them. - Check for:
- Hardcoded API keys, DB passwords, private keys in source.
.env/*.pemfiles tracked in git.- Secrets in CI config (
.github/workflows/*.yml, etc.) as plaintext instead of secrets store. - Secrets in Dockerfiles / docker-compose.
- Secrets logged in error messages or stack traces.
- Missing secrets management: no Vault, AWS Secrets Manager, GCP Secret Manager, sealed-secrets, or equivalent at team+ tier.
- Long-lived credentials where short-lived (STS, OIDC federation) is available.
5. Cryptography
- Check for:
- Weak algorithms: MD5, SHA1 for auth or signatures; DES, 3DES, RC4; ECB mode; RSA < 2048; ECC with weak curves.
- Static IVs / nonces for AES-GCM, ChaCha20-Poly1305, or any mode that requires uniqueness.
- Homegrown crypto primitives (rolling your own encryption, signing, or key derivation).
- TLS: wildcard cert acceptance,
verify=false,InsecureSkipVerify, deprecated protocols (TLS < 1.2). - Missing HSTS at the edge.
- Random number generation from non-CSPRNG sources (
Math.random,rand(),random.random()for security purposes).
6. Session management
- Check for:
- Cookies missing
Secure,HttpOnly,SameSiteattributes (at minimumSameSite=Lax). - Session IDs in URLs.
- No session invalidation on logout.
- No session rotation on login / privilege change.
- Excessive session lifetime (> 30 days absolute, > 24h sliding at team+ tier for sensitive apps).
- Concurrent session limits absent at scalable tier.
- Cookies missing
7. Transport and headers
- HTTPS everywhere. No plain HTTP endpoints accepting credentials or cookies.
- Security headers:
Strict-Transport-Security(max-age ≥ 6 months, includeSubDomains recommended).Content-Security-Policy— must exist at team+ tier, must not useunsafe-inlineorunsafe-evalat scalable tier without explicit rationale.X-Content-Type-Options: nosniff.X-Frame-Options: DENYorSAMEORIGIN(or CSPframe-ancestors).Referrer-Policyset to a conservative value.- Absence of
X-Powered-By,Serverversion disclosure.
- CORS:
Access-Control-Allow-Origin: *combined with credentials or sensitive endpoints → critical.- Reflected origins without allowlist → high.
- CSRF: state-changing endpoints (non-idempotent) must either use non-cookie auth (bearer token) or CSRF tokens / double-submit / SameSite=Strict.
8. Logging and incident response
- Check for:
- Logs containing passwords, tokens, full credit card numbers, full national IDs, health data. Use
mcp__gitnexus__queryto find log call sites passing user objects directly. - Absence of auth-event logging (login success/failure, MFA, privilege change) at team+ tier.
- Logs written to local disk only without shipping (at scalable tier).
- Logs containing passwords, tokens, full credit card numbers, full national IDs, health data. Use
9. Dependencies and build
This overlaps with supply-chain-audit. Do a quick pass and defer deep analysis:
- Known-vulnerable dependencies flagged by package manager advisories.
- Lockfile missing or not committed.
- Build scripts executing arbitrary network fetches.
10. Client-side (if applicable)
- XSS:
- React/Vue/Angular:
dangerouslySetInnerHTML,v-html,bypassSecurityTrustHtmlon user content. - Server-rendered: unescaped interpolation in templates.
- React/Vue/Angular:
- Browser storage of sensitive data: access tokens in
localStorage(stolen by any XSS) vs. cookies withHttpOnly. - Client-side routing: authorization decisions made only on the client.
Severity classification
| Severity | Meaning | Examples |
|---|---|---|
| critical | Direct path to full compromise. | RCE, SQLi with data access, auth bypass, plaintext passwords, exposed private keys. |
| high | Significant weakening requiring modest chaining or user interaction. | Stored XSS, IDOR on sensitive resource, weak crypto, missing MFA on admin. |
| medium | Defense-in-depth gap; requires specific conditions. | Missing CSP, verbose error messages, weak session rotation. |
| low | Best-practice deviation with limited impact. | Missing X-Content-Type-Options, excessive session lifetime. |
| info | Observation with no direct risk. | Library in use has a known CVE not exploitable in this configuration. |
Blocking thresholds by tier
prototype: critical blocks launch.team: critical + high block launch.scalable: critical + high + medium block launch.
Output format
For each finding:
- id: SEC-<NNN>
severity: critical | high | medium | low | info
category: authentication | authorization | input-validation | secrets | crypto | session | transport | logging | dependencies | xss | csrf | ssrf | other
title: <short imperative phrase>
location: <file:line, or "multiple" with list>
description: |
<what the gap is, why it matters, realistic attacker scenario>
evidence:
- <code snippet>
- <gitnexus finding if applicable>
remediation:
plan_mode: |
<concrete steps to fix, specific to this codebase>
edit_mode: |
<diff or patch, or command sequence>
references:
- OWASP ASVS <section>
- CWE-<n>
- <RFC / spec link if relevant>
blocker_at_tier: [<tiers where this blocks launch>]
End with a dimension summary:
## Security Summary
Reviewed: <categories covered>
Findings: <N critical, N high, N medium, N low, N info>
Top 3 risks:
1. <id> — <title>
2. <id> — <title>
3. <id> — <title>
Not assessed: <categories skipped and why>
Example findings
Example 1 — Password storage with MD5
- id: SEC-001
severity: critical
category: authentication
title: "Passwords stored with unsalted MD5 — trivially reversible via rainbow tables"
location: "src/auth/user.py:88"
description: |
`hash_password` calls `hashlib.md5(password.encode()).hexdigest()` and
stores the result in `users.password_hash`. MD5 is cryptographically
broken for password storage: a 12-character alphanumeric password is
recoverable in seconds against modern GPUs, and unsalted MD5 means
precomputed rainbow tables reverse the top 10M passwords instantly.
Every user's password must be considered compromised and rotated the
moment a DB dump is leaked.
evidence:
- |
# src/auth/user.py:88
def hash_password(password: str) -> str:
return hashlib.md5(password.encode()).hexdigest()
remediation:
plan_mode: |
Migrate to argon2id (preferred) or bcrypt via `argon2-cffi` or
`bcrypt`. Strategy: (1) on next login, re-hash with argon2 and
flag `needs_rotation=false`. (2) Invalidate all sessions and force
password reset for users who haven't logged in within N days.
(3) After migration window, drop the MD5 fallback.
edit_mode: |
Requires confirmation: this changes the auth flow, invalidates
sessions, and forces a reset campaign. Coordinate with ops.
references:
- "OWASP ASVS 2.4 — Credential storage"
- "NIST SP 800-63B §5.1.1.2"
- "CWE-916"
blocker_at_tier: [prototype, team, scalable]
Example 2 — IDOR on order detail endpoint
- id: SEC-014
severity: high
category: authorization
title: "GET /api/orders/:id returns any order without checking ownership"
location: "src/routes/orders.ts:42"
description: |
The handler fetches the order by id and returns it if found, without
verifying the requesting user owns (or is otherwise entitled to) it.
Order IDs are sequential integers, so an authenticated user can
enumerate /api/orders/1, /api/orders/2, ... and read every order in
the system — shipping addresses, prices, items, tax IDs.
evidence:
- |
// src/routes/orders.ts:42
app.get('/api/orders/:id', requireAuth, async (req, res) => {
const order = await db.orders.findByPk(req.params.id);
res.json(order); // no ownership check
});
remediation:
plan_mode: |
Add an ownership predicate: `WHERE id = :id AND user_id = :user_id`.
For admin/support access, add an explicit role gate that's
auditable. Additionally, switch order IDs from sequential integers
to ULIDs to reduce enumeration damage if the check regresses.
edit_mode: |
Safe diff: add `.where({ user_id: req.user.id })`. Apply similar
checks to all other :id-scoped endpoints in the same router.
references:
- "OWASP ASVS 4.1 — General access control"
- "OWASP API Security Top 10 2023 — API1 BOLA"
- "CWE-639"
blocker_at_tier: [team, scalable]
Example 3 — JWT verification accepts alg: none
- id: SEC-022
severity: critical
category: authentication
title: "JWT library accepts tokens signed with alg=none"
location: "src/middleware/auth.js:18"
description: |
The JWT verification call uses `jwt.verify(token, SECRET)` without
restricting accepted algorithms. Older versions of the library, and
several ports, default to accepting `alg: none` — an attacker can
forge tokens with arbitrary claims and a blank signature, bypassing
auth entirely. Even on versions that default to disallowing `none`,
not specifying `algorithms:` opt-in keeps the surface broad
(key-confusion attacks between HS256 and RS256 become possible).
evidence:
- |
// src/middleware/auth.js:18
const decoded = jwt.verify(token, SECRET);
// should be: jwt.verify(token, PUBLIC_KEY, { algorithms: ['RS256'] })
remediation:
plan_mode: |
1. Pass `{ algorithms: ['RS256'] }` (or the single algorithm in
actual use) to every jwt.verify call.
2. Upgrade jsonwebtoken to the latest version.
3. Add a test that asserts a token with alg=none is rejected.
edit_mode: |
Safe to apply. Adds algorithms allowlist and the corresponding
negative test. Confirm the allowlist matches the issuing library.
references:
- "OWASP JSON Web Token Cheat Sheet"
- "CVE-2015-9235 (historical but illustrative)"
- "RFC 7518 §3.6"
blocker_at_tier: [prototype, team, scalable]
Edit-mode remediation
Apply fixes in this order (safest first):
- Adding missing security headers (low risk, no behavior change).
- Upgrading crypto primitives to safe defaults (if API-compatible).
- Adding input validation / schema checks.
- Adding authorization checks on unprotected endpoints (test thoroughly — this changes behavior).
- Rotating secrets (requires coordination with ops; do not auto-apply).
- Auth flow changes (always require explicit per-change confirmation).
For any remediation that rotates a credential, changes an auth flow, or alters a trust boundary: stop, show the proposed diff, and require explicit confirmation before applying. These are not reversible by a git revert in production — they affect users actively logged in.
Do not
- Do not run active scans against production. This skill is for code + config review.
- Do not claim "no vulnerabilities found" — always phrase as "no findings in the categories reviewed".
- Do not propose security theatre (e.g. adding
X-XSS-Protection: 1— it's deprecated and can introduce its own issues). - Do not dedupe findings that look similar but have different root causes. The orchestrator will dedupe cross-skill.