Security Verify — Verification Workflows
Run security verification checks: pattern scanning, OWASP compliance, and vulnerability assessment.
Usage
/security-verify # Default: run scan mode
/security-verify scan [path] # Pattern-based security scanning (SAST)
/security-verify dast <url> # Dynamic testing against running app (DAST)
/security-verify owasp # OWASP Top 10 compliance check
/security-verify assess # Vulnerability CVSS scoring + remediation
/security-verify audit # Adversarial logic-level code review (CWE + CVSS + exploit)
/security-verify full # scan + audit combined (use for /health or manual deep check)
Mode: scan
Run pattern-based security scanning against the codebase.
What It Checks
- Secret Detection — Hardcoded credentials, API keys, private keys
- SQL Injection — String interpolation in queries, raw SQL
- XSS — Disabled auto-escaping, innerHTML, unsafe template filters
- Command Injection — Unsafe subprocess/exec patterns
- Insecure Deserialization — Unsafe deserializers
- Weak Cryptography — MD5, SHA1, weak random for security use
- Multi-Tenant Violations — tenant_id from request, missing tenant filters
- Cookie Issues — Missing __Host- prefix, missing samesite
Scan Execution
Run the scanner script against target path:
# Full scan — manual usage, scans entire directory
bash "$HOME/.claude/skills/security-verify/lib/scanner-runner.sh" "${TARGET_PATH:-.}"
# Staged-only scan — pre-commit context, scans only git-staged files
bash "$HOME/.claude/skills/security-verify/lib/scanner-runner.sh" --staged
Use --staged when invoked from /pre-commit to limit scope to the current commit's changes.
Full-path scanning is for standalone audits.
Review findings, assess severity, and provide fix recommendations.
Dependency Audit
After pattern scan, check for known CVEs:
# Use filtered requirements file to audit only public packages.
if command -v uv &>/dev/null && ([ -f uv.lock ] || [ -f pyproject.toml ]); then
if uv export --no-hashes --frozen > /tmp/raw-reqs.txt 2>/dev/null; then :; else
uv run pip freeze > /tmp/raw-reqs.txt 2>/dev/null || true
fi
uv run --with pip-audit pip-audit -r /tmp/pip-audit-reqs.txt 2>/dev/null || true
elif command -v pip-audit &>/dev/null; then
pip-audit --local 2>/dev/null || true
else
echo "pip-audit not installed"
fi
npm audit --production 2>/dev/null || echo "No package.json"
Report Format
Generate a markdown report with severity counts, findings with file:line references, and fix recommendations.
Mode: dast
Dynamic Application Security Testing against a running application. Tests live HTTP endpoints rather than reading source files.
Prerequisites
- Application must be running and accessible at the provided URL
curl (always available, zero extra deps)
nuclei (optional, for deeper template-based scanning): brew install nuclei
python3 (required if using --nuclei, for JSON parsing)
What It Checks
Tier 1 — curl-based (always runs):
| # |
Category |
What it checks |
Severity |
| 1 |
HTTP Security Headers |
HSTS, CSP, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy |
LOW–HIGH |
| 2 |
Cookie Security |
Secure, HttpOnly, SameSite flags |
MEDIUM–HIGH |
| 3 |
CORS |
Wildcard origins, evil origin reflection |
HIGH–CRITICAL |
| 4 |
TLS/SSL |
Protocol version (≥TLS 1.2), cert expiry |
MEDIUM–HIGH |
| 5 |
Information Disclosure |
Server version header, X-Powered-By, exposed paths (/.env, /.git, /debug, /admin) |
LOW–HIGH |
| 6 |
Open Redirects |
Redirect parameter injection test |
HIGH |
| 7 |
HTTP Methods |
TRACE enabled, OPTIONS enumeration |
LOW |
Tier 2 — nuclei (when installed):
| # |
Category |
What it checks |
| 8 |
CVE patterns |
Known vulnerability templates for http/, ssl/, misconfiguration/ |
| 9 |
Auth bypass |
Default credentials, auth misconfiguration templates |
DAST Execution
# Tier 1 only (curl-based, zero deps)
bash "$HOME/.claude/skills/security-verify/lib/dast-runner.sh" "http://localhost:8000"
# Tier 1 + Tier 2 (requires nuclei installed)
bash "$HOME/.claude/skills/security-verify/lib/dast-runner.sh" "http://localhost:8000" --nuclei
# Custom per-check timeout (default: 5s)
bash "$HOME/.claude/skills/security-verify/lib/dast-runner.sh" "http://localhost:8000" --timeout 3
Report Format — Active vs Potential
Findings are labelled to distinguish confidence level:
ACTIVE — Confirmed by server response. Remediate now. (e.g., server returned missing CSP header)
POTENTIAL — Suspicious behavior requiring manual verification. (e.g., redirect parameter exists but may validate destinations)
Exit codes: 0 = no critical/high findings, 1 = critical/high found, 2 = URL unreachable.
DAST vs SAST
|
SAST (scan) |
DAST (dast) |
| Input |
Source files |
Running server |
| Finds |
Potential vulnerabilities |
Active misconfigurations |
| Deps |
None (bash grep) |
curl + optional nuclei |
| When |
Any time |
App must be running |
| Pre-commit |
Yes (default) |
Optional (--dast <url>) |
Mode: owasp
Systematic OWASP Top 10 2021 compliance verification.
Categories
| ID |
Category |
Key Checks |
| A01 |
Broken Access Control |
Authorization on every endpoint, no IDOR, CORS config |
| A02 |
Cryptographic Failures |
TLS 1.2+, Argon2/bcrypt hashing, no weak algorithms |
| A03 |
Injection |
Parameterized SQL, safe subprocess usage |
| A04 |
Insecure Design |
Rate limiting, account lockout, threat model |
| A05 |
Security Misconfiguration |
Debug off, security headers, no defaults |
| A06 |
Vulnerable Components |
No critical CVEs, deps up to date |
| A07 |
Auth Failures |
Strong passwords, session timeout, MFA |
| A08 |
Integrity Failures |
Safe deserialization, yaml.safe_load |
| A09 |
Logging Failures |
Auth events logged, no PII in logs |
| A10 |
SSRF |
URL validation, private IPs blocked |
Verification Process
For each category:
- Run automated checks (grep patterns per category)
- Review findings
- Mark Pass/Partial/Fail with evidence
- Generate compliance report
Mode: assess
Deep vulnerability analysis with CVSS scoring and remediation strategies.
Assessment Workflow
- Classify vulnerability type (injection, auth, data exposure, XSS, etc.)
- Evaluate exploitability (Easy/Medium/Hard based on attack vector, complexity, privileges)
- Assess impact (Confidentiality/Integrity/Availability: None/Low/High)
- Calculate CVSS v3.1 score using base metrics
- Prioritize using risk matrix (severity x exploitability -> P0-P3)
- Recommend remediation with code examples
CVSS Score Ranges
| Score |
Severity |
| 0.0 |
None |
| 0.1-3.9 |
Low |
| 4.0-6.9 |
Medium |
| 7.0-8.9 |
High |
| 9.0-10.0 |
Critical |
Priority SLAs
| Priority |
SLA |
Criteria |
| P0 |
24 hours |
Critical+Easy or High+Easy |
| P1 |
7 days |
Critical+Hard or High+Medium |
| P2 |
30 days |
Medium or High+Hard |
| P3 |
90 days |
Low severity |
Mode: audit
Adversarial logic-level code review. Reads code deeply to find vulnerabilities that grep-based SAST misses — auth bypass, IDOR, race conditions, session fixation, missing ownership checks.
Run as a focused subagent (spawn fresh context to avoid polluting the main conversation with large finding sets). When invoked, spawn an Agent with subagent_type: general-purpose, model: sonnet, and pass the target scope.
Mindset
Assume the code is hostile until proven otherwise. Find vulnerabilities a real attacker would exploit. "If you can't write the exploit scenario in one sentence, downgrade severity."
- Injection: trace user-controlled input → all SQL sinks (raw
text(), op.execute(), f-strings in queries). Alembic rule: each op.execute() must be a single statement — two statements separated by ; fail on asyncpg.
- Auth: check every route for
Depends(get_current_user) or equivalent. Routes missing auth on sensitive operations (write, delete, admin functions) are CRITICAL.
- IDOR: for every endpoint accepting an object ID (company_id, person_id, job_id), verify ownership check: does the handler confirm the object belongs to the authenticated user/tenant?
- Race conditions: check background job handlers and Celery tasks for TOCTOU patterns on shared resources.
General checks (adapt to target):
- Sensitive data exposure: PII in logs, cleartext credentials in source, debug endpoints accessible in prod
- Input validation: Pydantic model field constraints present at API boundaries (length, range, format)
- CSRF: state-changing endpoints behind Traefik — session cookie
SameSite set?
- Insecure deserialization: no
yaml.load() without Loader=yaml.SafeLoader; no unsafe deserialization of untrusted binary data
- Security misconfiguration: debug mode off,
ALLOWED_HOSTS not *, verbose error messages suppressed
Report Format
Each finding must include:
- ID:
SEC-NNN (sequential)
- CWE:
CWE-XXX — Name (e.g., CWE-89 — SQL Injection)
- Severity:
CRITICAL / HIGH / MEDIUM / LOW with CVSS-ish reasoning
- Location:
file.py:line
- Exploit scenario: one sentence describing the attack
- Fix: concrete code-level remediation
When to use
- Manual deep audit before major releases
- After
/health security (scan passes but audit finds logic flaws)
- When security-sensitive PR touches auth, session, IDOR-prone endpoints
NOT for pre-commit — use scan there. audit takes minutes; scan takes seconds.
Mode: full
Runs scan + audit sequentially. Use for /health full or when you want complete security coverage in one command.
1. Run scan (SAST grep patterns + dependency audit)
2. Run audit (adversarial logic-level review)
3. Merge findings into unified report ordered by severity
Workflow Integration
Recommended security workflow:
- Implement →
/security [mode] — get implementation guidance
- Scan →
/security-verify scan — SAST: fast grep-based check (seconds, runs in pre-commit)
- Audit →
/security-verify audit — adversarial logic review (minutes, run manually or via /health)
- Dynamic →
/security-verify dast <url> — DAST: test running app (staging/local)
- Comply →
/security-verify owasp — verify OWASP Top 10 compliance
- Assess →
/security-verify assess — CVSS score and prioritize findings
- Full →
/security-verify full — scan + audit combined (use for /health full)
/security-verify scan is called by /pre-commit automatically. /security-verify dast is optional — use --dast <url> with /pre-commit when a local dev server is running. /security-verify audit and full are called by /health security and /health full.
Gotchas
- Bandit requires Python ≤3.13 — Python 3.14 removed
.s/.n AST attributes; bandit ≤1.8.x crashes on every file and silently reports 0 findings. Use python3.13 -m bandit (bandit 1.9.4 installed there).
scanner-runner.sh --staged requires bash 4+ (mapfile); macOS ships bash 3.2 — use full scan mode instead of --staged on macOS.
- False positives in
projects/ (JSONL session transcripts), .archive/, and .venv/ — assess as FP, do not report as real issues.
- JS dependency audit gates on CRITICAL only (
pnpm audit --audit-level=critical); HIGH vulns in transitive/dev deps (ReDoS in build tools, prototype pollution in bundlers) are noise, not runtime-exploitable — surface them informationally but do not block.
- Python
pip-audit runs with no severity threshold (all vulns surfaced + gated) — different ecosystem from JS, more conservative CVE scoring, smaller dep trees.
1---
2name: security-verify
3description: Run security verification — SAST pattern scanning, DAST against a running app, OWASP Top 10 compliance, CVSS assessment, and adversarial code audit. Use before commit/push or when checking code for vulnerabilities. Trigger on "security scan", "is this vulnerable", "OWASP check", "security verify", "scan for vulnerabilities".
4allowed-tools: Read, Bash, Grep, Glob
5---
6
7# Security Verify — Verification Workflows
8
9Run security verification checks: pattern scanning, OWASP compliance, and vulnerability assessment.
10
11## Usage
12
13```
14/security-verify # Default: run scan mode
15/security-verify scan [path] # Pattern-based security scanning (SAST)
16/security-verify dast <url> # Dynamic testing against running app (DAST)
17/security-verify owasp # OWASP Top 10 compliance check
18/security-verify assess # Vulnerability CVSS scoring + remediation
19/security-verify audit # Adversarial logic-level code review (CWE + CVSS + exploit)
20/security-verify full # scan + audit combined (use for /health or manual deep check)
21```
22
23## Mode: scan
24
25Run pattern-based security scanning against the codebase.
26
27### What It Checks
28
291. **Secret Detection** — Hardcoded credentials, API keys, private keys
302. **SQL Injection** — String interpolation in queries, raw SQL
313. **XSS** — Disabled auto-escaping, innerHTML, unsafe template filters
324. **Command Injection** — Unsafe subprocess/exec patterns
335. **Insecure Deserialization** — Unsafe deserializers
346. **Weak Cryptography** — MD5, SHA1, weak random for security use
357. **Multi-Tenant Violations** — tenant_id from request, missing tenant filters
368. **Cookie Issues** — Missing \_\_Host- prefix, missing samesite
37
38### Scan Execution
39
40Run the scanner script against target path:
41
42```bash
43# Full scan — manual usage, scans entire directory
44bash "$HOME/.claude/skills/security-verify/lib/scanner-runner.sh" "${TARGET_PATH:-.}"
45
46# Staged-only scan — pre-commit context, scans only git-staged files
47bash "$HOME/.claude/skills/security-verify/lib/scanner-runner.sh" --staged
48```
49
50Use `--staged` when invoked from `/pre-commit` to limit scope to the current commit's changes.
51Full-path scanning is for standalone audits.
52
53Review findings, assess severity, and provide fix recommendations.
54
55### Dependency Audit
56
57After pattern scan, check for known CVEs:
58
59```bash
60# Use filtered requirements file to audit only public packages.
61if command -v uv &>/dev/null && ([ -f uv.lock ] || [ -f pyproject.toml ]); then
62 if uv export --no-hashes --frozen > /tmp/raw-reqs.txt 2>/dev/null; then :; else
63 uv run pip freeze > /tmp/raw-reqs.txt 2>/dev/null || true
64 fi
65 uv run --with pip-audit pip-audit -r /tmp/pip-audit-reqs.txt 2>/dev/null || true
66elif command -v pip-audit &>/dev/null; then
67 pip-audit --local 2>/dev/null || true
68else
69 echo "pip-audit not installed"
70fi
71npm audit --production 2>/dev/null || echo "No package.json"
72```
73
74### Report Format
75
76Generate a markdown report with severity counts, findings with file:line references, and fix recommendations.
77
78## Mode: dast
79
80Dynamic Application Security Testing against a running application. Tests live HTTP endpoints rather than reading source files.
81
82### Prerequisites
83
84- Application must be running and accessible at the provided URL
85- `curl` (always available, zero extra deps)
86- `nuclei` (optional, for deeper template-based scanning): `brew install nuclei`
87- `python3` (required if using `--nuclei`, for JSON parsing)
88
89### What It Checks
90
91**Tier 1 — curl-based (always runs):**
92
93| # | Category | What it checks | Severity |
94| --- | ---------------------- | --------------------------------------------------------------------------------------- | ------------- |
95| 1 | HTTP Security Headers | HSTS, CSP, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy | LOW–HIGH |
96| 2 | Cookie Security | Secure, HttpOnly, SameSite flags | MEDIUM–HIGH |
97| 3 | CORS | Wildcard origins, evil origin reflection | HIGH–CRITICAL |
98| 4 | TLS/SSL | Protocol version (≥TLS 1.2), cert expiry | MEDIUM–HIGH |
99| 5 | Information Disclosure | Server version header, X-Powered-By, exposed paths (/.env, /.git, /debug, /admin) | LOW–HIGH |
100| 6 | Open Redirects | Redirect parameter injection test | HIGH |
101| 7 | HTTP Methods | TRACE enabled, OPTIONS enumeration | LOW |
102
103**Tier 2 — nuclei (when installed):**
104
105| # | Category | What it checks |
106| --- | ------------ | ---------------------------------------------------------------- |
107| 8 | CVE patterns | Known vulnerability templates for http/, ssl/, misconfiguration/ |
108| 9 | Auth bypass | Default credentials, auth misconfiguration templates |
109
110### DAST Execution
111
112```bash
113# Tier 1 only (curl-based, zero deps)
114bash "$HOME/.claude/skills/security-verify/lib/dast-runner.sh" "http://localhost:8000"
115
116# Tier 1 + Tier 2 (requires nuclei installed)
117bash "$HOME/.claude/skills/security-verify/lib/dast-runner.sh" "http://localhost:8000" --nuclei
118
119# Custom per-check timeout (default: 5s)
120bash "$HOME/.claude/skills/security-verify/lib/dast-runner.sh" "http://localhost:8000" --timeout 3
121```
122
123### Report Format — Active vs Potential
124
125Findings are labelled to distinguish confidence level:
126
127- **`ACTIVE`** — Confirmed by server response. Remediate now. (e.g., server returned missing CSP header)
128- **`POTENTIAL`** — Suspicious behavior requiring manual verification. (e.g., redirect parameter exists but may validate destinations)
129
130Exit codes: `0` = no critical/high findings, `1` = critical/high found, `2` = URL unreachable.
131
132### DAST vs SAST
133
134| | SAST (`scan`) | DAST (`dast`) |
135| ---------- | ------------------------- | ------------------------- |
136| Input | Source files | Running server |
137| Finds | Potential vulnerabilities | Active misconfigurations |
138| Deps | None (bash grep) | curl + optional nuclei |
139| When | Any time | App must be running |
140| Pre-commit | Yes (default) | Optional (`--dast <url>`) |
141
142## Mode: owasp
143
144Systematic OWASP Top 10 2021 compliance verification.
145
146### Categories
147
148| ID | Category | Key Checks |
149| --- | ------------------------- | ----------------------------------------------------- |
150| A01 | Broken Access Control | Authorization on every endpoint, no IDOR, CORS config |
151| A02 | Cryptographic Failures | TLS 1.2+, Argon2/bcrypt hashing, no weak algorithms |
152| A03 | Injection | Parameterized SQL, safe subprocess usage |
153| A04 | Insecure Design | Rate limiting, account lockout, threat model |
154| A05 | Security Misconfiguration | Debug off, security headers, no defaults |
155| A06 | Vulnerable Components | No critical CVEs, deps up to date |
156| A07 | Auth Failures | Strong passwords, session timeout, MFA |
157| A08 | Integrity Failures | Safe deserialization, yaml.safe_load |
158| A09 | Logging Failures | Auth events logged, no PII in logs |
159| A10 | SSRF | URL validation, private IPs blocked |
160
161### Verification Process
162
163For each category:
164
1651. Run automated checks (grep patterns per category)
1662. Review findings
1673. Mark Pass/Partial/Fail with evidence
1684. Generate compliance report
169
170## Mode: assess
171
172Deep vulnerability analysis with CVSS scoring and remediation strategies.
173
174### Assessment Workflow
175
1761. **Classify** vulnerability type (injection, auth, data exposure, XSS, etc.)
1772. **Evaluate exploitability** (Easy/Medium/Hard based on attack vector, complexity, privileges)
1783. **Assess impact** (Confidentiality/Integrity/Availability: None/Low/High)
1794. **Calculate CVSS v3.1 score** using base metrics
1805. **Prioritize** using risk matrix (severity x exploitability -> P0-P3)
1816. **Recommend remediation** with code examples
182
183### CVSS Score Ranges
184
185| Score | Severity |
186| -------- | -------- |
187| 0.0 | None |
188| 0.1-3.9 | Low |
189| 4.0-6.9 | Medium |
190| 7.0-8.9 | High |
191| 9.0-10.0 | Critical |
192
193### Priority SLAs
194
195| Priority | SLA | Criteria |
196| -------- | -------- | ---------------------------- |
197| P0 | 24 hours | Critical+Easy or High+Easy |
198| P1 | 7 days | Critical+Hard or High+Medium |
199| P2 | 30 days | Medium or High+Hard |
200| P3 | 90 days | Low severity |
201
202## Mode: audit
203
204Adversarial logic-level code review. Reads code deeply to find vulnerabilities that grep-based SAST misses — auth bypass, IDOR, race conditions, session fixation, missing ownership checks.
205
206**Run as a focused subagent** (spawn fresh context to avoid polluting the main conversation with large finding sets). When invoked, spawn an Agent with `subagent_type: general-purpose`, `model: sonnet`, and pass the target scope.
207
208### Mindset
209
210Assume the code is hostile until proven otherwise. Find vulnerabilities a real attacker would exploit. "If you can't write the exploit scenario in one sentence, downgrade severity."
211
212
213
214- Injection: trace user-controlled input → all SQL sinks (raw `text()`, `op.execute()`, f-strings in queries). Alembic rule: each `op.execute()` must be a single statement — two statements separated by `;` fail on asyncpg.
215- Auth: check every route for `Depends(get_current_user)` or equivalent. Routes missing auth on sensitive operations (write, delete, admin functions) are CRITICAL.
216- IDOR: for every endpoint accepting an object ID (company_id, person_id, job_id), verify ownership check: does the handler confirm the object belongs to the authenticated user/tenant?
217- Race conditions: check background job handlers and Celery tasks for TOCTOU patterns on shared resources.
218
219**General checks (adapt to target):**
220
221- Sensitive data exposure: PII in logs, cleartext credentials in source, debug endpoints accessible in prod
222- Input validation: Pydantic model field constraints present at API boundaries (length, range, format)
223- CSRF: state-changing endpoints behind Traefik — session cookie `SameSite` set?
224- Insecure deserialization: no `yaml.load()` without `Loader=yaml.SafeLoader`; no unsafe deserialization of untrusted binary data
225- Security misconfiguration: debug mode off, `ALLOWED_HOSTS` not `*`, verbose error messages suppressed
226
227### Report Format
228
229Each finding must include:
230
231- **ID**: `SEC-NNN` (sequential)
232- **CWE**: `CWE-XXX — Name` (e.g., `CWE-89 — SQL Injection`)
233- **Severity**: `CRITICAL / HIGH / MEDIUM / LOW` with CVSS-ish reasoning
234- **Location**: `file.py:line`
235- **Exploit scenario**: one sentence describing the attack
236- **Fix**: concrete code-level remediation
237
238### When to use
239
240- Manual deep audit before major releases
241- After `/health security` (scan passes but audit finds logic flaws)
242- When security-sensitive PR touches auth, session, IDOR-prone endpoints
243
244**NOT for pre-commit** — use `scan` there. `audit` takes minutes; `scan` takes seconds.
245
246## Mode: full
247
248Runs `scan` + `audit` sequentially. Use for `/health full` or when you want complete security coverage in one command.
249
250```
2511. Run scan (SAST grep patterns + dependency audit)
2522. Run audit (adversarial logic-level review)
2533. Merge findings into unified report ordered by severity
254```
255
256## Workflow Integration
257
258Recommended security workflow:
259
2601. **Implement** → `/security [mode]` — get implementation guidance
2612. **Scan** → `/security-verify scan` — SAST: fast grep-based check (seconds, runs in pre-commit)
2623. **Audit** → `/security-verify audit` — adversarial logic review (minutes, run manually or via /health)
2634. **Dynamic** → `/security-verify dast <url>` — DAST: test running app (staging/local)
2645. **Comply** → `/security-verify owasp` — verify OWASP Top 10 compliance
2656. **Assess** → `/security-verify assess` — CVSS score and prioritize findings
2667. **Full** → `/security-verify full` — scan + audit combined (use for /health full)
267
268`/security-verify scan` is called by `/pre-commit` automatically. `/security-verify dast` is optional — use `--dast <url>` with `/pre-commit` when a local dev server is running. `/security-verify audit` and `full` are called by `/health security` and `/health full`.
269
270## Gotchas
271
272- Bandit requires Python ≤3.13 — Python 3.14 removed `.s`/`.n` AST attributes; bandit ≤1.8.x crashes on every file and silently reports 0 findings. Use `python3.13 -m bandit` (bandit 1.9.4 installed there).
273- `scanner-runner.sh --staged` requires bash 4+ (`mapfile`); macOS ships bash 3.2 — use full scan mode instead of `--staged` on macOS.
274- False positives in `projects/` (JSONL session transcripts), `.archive/`, and `.venv/` — assess as FP, do not report as real issues.
275- JS dependency audit gates on CRITICAL only (`pnpm audit --audit-level=critical`); HIGH vulns in transitive/dev deps (ReDoS in build tools, prototype pollution in bundlers) are noise, not runtime-exploitable — surface them informationally but do not block.
276- Python `pip-audit` runs with no severity threshold (all vulns surfaced + gated) — different ecosystem from JS, more conservative CVE scoring, smaller dep trees.