| name | web-security |
| description | Web application security covering OWASP Top 10 (2021) — injection, broken auth, XSS, insecure design, security misconfiguration, vulnerable components, IDOR, SSRF, and more — with prose guidance and deterministic OWASP coverage scoring via executable script. Use proactively when reviewing web application or API security, running a pre-launch security checklist, performing post-incident gap analysis against OWASP Top 10, or any review touching authentication, authorization, injection, or session management. Run the OWASP scorer for deterministic coverage assessment. |
| version | 2.0.0 |
| source | derived from .claude/skills/security/web-security.md (v1.0); L3 OWASP scorer added 2026-05-20 |
| when_to_use | ["Web application security review","API security audit","Pre-launch security checklist","Post-incident gap analysis against OWASP Top 10","Any review touching authentication, authorization, injection, or session management"] |
| allowed-tools | ["Read","Grep","Glob","Bash"] |
Web Security
Comprehensive web application security patterns covering OWASP Top 10 (2021). Apply before code review, not after.
OWASP analysis is prose judgment — the model reasons about attack vectors, code patterns, and mitigations. OWASP coverage is deterministic — the script validates that every finding maps to a real OWASP category and reports which of the 10 categories have zero findings (the blind spots).
Never report a "clean" security review without running the coverage checker.
OWASP Top 10 (2021) — Quick Reference
| Code | Category | Core Risk |
|---|
| A01 | Broken Access Control | Unauthorized access, IDOR, privilege escalation |
| A02 | Cryptographic Failures | Plaintext storage, weak algorithms, missing TLS |
| A03 | Injection | SQL, NoSQL, OS, LDAP injection; XSS |
| A04 | Insecure Design | Missing threat model, no security requirements |
| A05 | Security Misconfiguration | Default creds, verbose errors, open CORS |
| A06 | Vulnerable and Outdated Components | CVE-carrying dependencies |
| A07 | Identification and Authentication Failures | Weak passwords, no MFA, session issues |
| A08 | Software and Data Integrity Failures | Unsigned updates, unsafe deserialization |
| A09 | Security Logging and Monitoring Failures | Undetected breaches, missing audit logs |
| A10 | Server-Side Request Forgery (SSRF) | Internal service access via user-controlled URLs |
Invocation — OWASP Coverage Scorer (L3 Script)
After identifying findings, assemble them as a JSON array and run the scorer. Consume its output only — the script source never enters context.
Format each finding:
[
{
"title": "Admin endpoint lacks authentication check",
"owasp": "A01",
"severity": "Critical",
"status": "open"
}
]
OWASP field: Use short codes A01–A10, or full OWASP 2021 category names (e.g. "Injection"), or common shorthands ("SSRF", "IDOR", "sqli", "authentication").
severity field (optional): Critical | High | Medium | Low
status field (optional): open | mitigated | accepted | n/a
Run via Bash (file argument):
python .claude/skills/security/web-security/scripts/owasp_score.py findings.json
Run via Bash (stdin):
echo '<json array>' | python .claude/skills/security/web-security/scripts/owasp_score.py -
The script outputs:
- A JSON object with
findings (normalized), category_counts (findings per category), gaps (uncovered categories), and a summary.
- An OWASP Top 10 Coverage markdown table showing finding counts and gaps.
- (Optional) A Severity Summary table if severity fields are present.
Error handling: Non-zero exit on unknown OWASP category, invalid severity, or malformed JSON. Fix the input and re-run.
What the agent does with the output:
- Check
gaps — any OWASP category with zero findings is a potential blind spot; document why it is N/A before accepting the gap.
- Address Critical and High open findings before signing off.
- Use the coverage table as an executive summary.
Vulnerability Patterns and Mitigations
A01 — Broken Access Control
app.get('/api/users/:id', (req, res) => {
return db.users.findById(req.params.id);
});
app.get('/api/users/:id', authenticate, (req, res) => {
if (req.user.id !== req.params.id && !req.user.isAdmin) {
return res.status(403).json({ error: 'Forbidden' });
}
return db.users.findById(req.params.id);
});
Checklist:
A02 — Cryptographic Failures
Checklist:
A03 — Injection
const q = `SELECT * FROM users WHERE id = ${userId}`;
const q = 'SELECT * FROM users WHERE id = ?';
const result = await db.query(q, [userId]);
Checklist:
A05 — Security Misconfiguration
app.use((err, req, res, next) => {
res.status(500).json({ error: err.stack });
});
app.use((err, req, res, next) => {
console.error(err);
res.status(500).json({ error: 'Internal server error' });
});
Security Headers Checklist:
A07 — Authentication Failures
app.post('/login', async (req, res) => { ... });
import rateLimit from 'express-rate-limit';
const loginLimiter = rateLimit({ windowMs: 15 * 60 * 1000, max: 5 });
app.post('/login', loginLimiter, async (req, res) => {
res.cookie('session', sessionId, { httpOnly: true, secure: true, sameSite: 'strict' });
});
A10 — SSRF
const response = await fetch(req.body.url);
const ALLOWED = ['api.trusted.com'];
const url = new URL(req.body.url);
if (!ALLOWED.includes(url.hostname)) throw new Error('Host not allowed');
const response = await fetch(url);
Review Workflow
- Map entry points — List every public and privileged endpoint
- Identify findings — For each entry point, check relevant OWASP categories
- Assemble findings JSON — Include
owasp category, severity, and status
- Run the coverage scorer —
python .claude/skills/security/web-security/scripts/owasp_score.py findings.json
- Address gaps — Every uncovered OWASP category needs a documented rationale (not just silence)
- Remediate by severity — Critical first; do not remediate in order of discovery
Anti-Generic Rules
- NEVER report a clean security review without running the coverage scorer
- NEVER fix only the top-priority finding — all Critical/High open items must be addressed before sign-off
- NEVER use client-side validation as a security control
- NEVER leave verbose error messages in production (stack traces are recon material)
- NEVER assume a WAF replaces code-level fixes
Self-Critique: "Did I run the scorer and inspect the gaps? Can I justify every gap as genuinely N/A, or did I just skip it? Would the A09 (Logging) category pass a pen test today?"