dev-security
Skill0 starsChanged 4 months agoMITView on GitHub
Use when a security audit of the codebase is needed. Use with /dev-security.
In this repository42 other files it gives its agents.
- .claude/CLAUDE.mdCLAUDE.md
- content-rewriteSkill
- content-writeSkill
- core-auditSkill
- core-bootstrapSkill
- core-commitSkill
- core-explainSkill
- core-finalizeSkill
- core-orchestrateSkill
- core-pullSkill
- core-setupSkill
- core-updateSkill
- design-convertSkill
- design-shipSkill
- design-tokensSkill
- dev-inspectSkill
- dev-learnSkill
- dev-manualSkill
- dev-optimizeSkill
- dev-shipSkill
- dev-tweakSkill
- game-debugSkill
- game-optimizeSkill
- game-shipSkill
- game-tweakSkill
- marketing-contentSkill
- marketing-researchSkill
- marketing-screenshotsSkill
- project-addSkill
- project-appSkill
- project-memorySkill
- project-planSkill
- project-removeSkill
- project-researchSkill
- project-seedSkill
- project-syncSkill
- project-todoSkill
- project-tunnelSkill
- team-issuesSkill
- team-outsourceSkill
- team-reviewSkill
- team-verifySkill
The file
We split this skill into the rules it gives an agent
10 rules. About 0 are common, 3 are distinctive, and 7 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈3
Distinctive · estimate
This author's own choices. Worth a look.
7
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 70
No matches → continue to Step 1.
- Very specific: line 95
No ship-triage file, but .project/features/{feature}/feature.json#files[] exists → scope = that file list.
- Very specific: line 122
Read .project/project.json (if it exists).
- Very specific: line 139
If project.json does not exist → continue without it (backwards compatible).
- Very specific: line 177
Every later phase boundary patches updatedAt + phase (and its own fields) into this same file — resolve via mainRoot from here on, never a …
- Very specific: line 192
Run osv-scanner --format=json scan source ./ → .project/security/osv-report.json.
- Very specific: line 193
Run semgrep scan --config auto --json --quiet → .project/security/semgrep-report.json.
- Very specific: line 194
Run gitleaks detect --report-format json --report-path .project/security/gitleaks-report.json (secrets in working tree + git history).
- Distinctive: line 259
If the relevant category's scanner re-verified the item as fixed (its own findings/verdict no longer show it) → report it as resolved, not …
- Distinctive: line 344
Follow the Language Policy in CLAUDE.md.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Security Audit
Deep security audit — OWASP Top 10:2025 + supply-chain/SAST/secret tooling: scope → tooling → 10 parallel scanners → aggregated report → 3 fix strategies → worktree'd implementation.
Process
Phase tracking — first action of the skill: call TaskCreate with these 6 items (status
pending), then use TaskUpdate to set each phase in_progress at start and completed at end.
During context compaction the task list remains visible — no risk of forgotten phases. If
ToolSearch cannot resolve TaskCreate/TaskUpdate (unavailable this session), skip phase
tracking silently and proceed — the audit-state file's own phase field (§ Step 5 below, patched
at every phase boundary) remains the durable resumability signal regardless.
Durable audit state (lightweight, not a full ship checkpoint) — beyond the compaction-safe
TaskCreate list, PHASE 1 writes .project/security/audit-{id}.json and every later phase patches
it at each boundary. Unlike shared/SHIP-CHECKPOINT.md's ship pipelines, this is a plain state file
this skill owns and resumes itself — there is no route subcommand, no ledger, no board signal. It
is kept on completion (it is the durable audit record, not a transient in-flight marker).
- PHASE 1: Scope
- PHASE 2: Tooling scan
- PHASE 2b: Parallel OWASP scan
- PHASE 3: Aggregation & Report
- PHASE 4: Fix Plans
- PHASE 5: Selection & Implementation
PHASE 1: Scope
Todo: call
ToolSearch query="select:TaskCreate,TaskUpdate,Workflow"first — deferred tools are unusable without their schemas, and PHASE 2b needsWorkflowloaded regardless of which branch below fires. IfTaskCreate/TaskUpdatedon't resolve, skip task tracking and continue —Workflowis still required.
Step 0: Resume check (before seeding tasks)
ls .project/security/audit-*.json (glob, may be empty). For each match with status: "running":
updatedAtwithin the last 24h → AskUserQuestion — header: "Resume audit", question: "An in-progress audit from {relative time} exists ({phase}, scope: {scope.choice}). Resume it?":- "Resume (Recommended)" — load the audit state, re-seed
TaskCreate(phases before the recordedphasecreatedcompleted, the restpending— never seed all 6pendingthen flip), jump straight to thatphasebelow (PHASE 2b's scan Workflow getsresume.scannersfromscannersalready collected; PHASE 4 similarly skips ifplansis already populated). - "Restart fresh" — leave the stale file on disk (do not delete — it's evidence of an interruption), fall through to Step 1.
- "Inspect first" — print the audit state's
scope/phase/aggregate.overallScore(if any), re-ask.
- "Resume (Recommended)" — load the audit state, re-seed
- Older than 24h, or
status: "complete"→ skip silently (stale or already-done), continue to Step 1.
No matches → continue to Step 1.
Todo: call
TaskCreatewith the 6 phase items (see above) — on a resume, seed per the re-seed rule just described. Mark PHASE 1 →in_progressviaTaskUpdate.
Step 1: Detect tech stack
Project CLAUDE.md or .project/project.json#stack already documents the stack → reuse it, skip
the scan. Otherwise, scan the project for languages, frameworks, and entry points:
- Glob for
package.json,requirements.txt,composer.json,go.mod,Cargo.toml,Gemfile - Identify framework (Express, Django, Laravel, Rails, Next.js, etc.)
- Map source directories (controllers, routes, API handlers, middleware)
Step 2: Confirm scope
Explicit feature-arg auto-resolve — when invoked as /dev-security {feature} (an explicit
feature-name arg), resolve scope automatically, no modal:
.project/security/ship-triage-{feature}.jsonexists → scope = "Ship-triage follow-up":feature.json#files[]for{feature}— check.project/features/{feature}/feature.jsonfirst, then.project/features/archive/*-{feature}/feature.json(ship-triage is inherently post-ship, so the archived path is the common case, not the exception); preloadtriage.confirmedfrom the ship-triage file as known findings (see Step 4). Log:Scope: ship-triage follow-up voor {feature} (auto, feature-arg gegeven).- No ship-triage file, but
.project/features/{feature}/feature.json#files[]exists → scope = that file list. Log:Scope: {feature}#files[] (auto, feature-arg gegeven). - Neither exists → fall back to the most recent completed audit's
scope.files[]for this feature if one exists in.project/security/audit-*.json. - None of the above resolve anything → fall through to the modal below (the only remaining case where scope is genuinely ambiguous even with a feature name given).
No feature-arg (bare /dev-security) → always ask. AskUserQuestion:
- header: "Scan Scope"
- question: "Which parts of the codebase do you want to scan?"
- options:
- "Full codebase (Recommended)" — Scan everything except node_modules/vendor/dist
- "Backend/API only" — Focus on server-side code
- "Changed features only" — Only pipeline files of DONE/shipped backlog features
- "Specific directory" — Enter a path
- multiSelect: false
"Changed features only": read .project/backlog.json (+ .project/archive/backlog-archive.json), take features with status DONE or shipped, and collect their files[] from .project/features/{name}/feature.json. That union is the file list for step 3. No backlog or no feature.json files → fall back to "Full codebase" with a log line. Faster targeted audit between full scans; PHASE 2b tooling (lockfiles, git history) still runs repo-wide.
Step 3: Build file list
Collect relevant source files (exclude dependencies, build output, static assets). Group by type: routes/controllers, models/data, config, middleware, templates/views.
Step 4: Load project context
Read .project/project.json (if it exists). Extract:
endpoints— API surface (method, path, auth per route)data.entities— data model (entity names, fields, relations)
Read .project/project-context.json (if it exists). Extract:
context.patterns— auth patterns, middleware setup
Assemble OWASP_CONTEXT (pass to scanner agents in PHASE 2b):
API SURFACE: {endpoints of "not available — scanners must discover endpoints themselves"}
DATA MODEL: {entities of "not available"}
AUTH PATTERNS: {auth-related patterns of "not available"}If project.json does not exist → continue without it (backwards compatible).
Ship-triage preload (only on the "Ship-triage follow-up" scope choice): read
.project/security/ship-triage-{feature}.json, carry its triage.confirmed[] array forward as
shipTriageRef in the audit state — PHASE 3 folds these in as already-known findings (no
duplicate scanner re-discovery credit needed, but they still count toward the report) and PHASE 4's
findings file includes them.
Step 5: Create the audit state
mkdir -p .project/security
main_root=$(git worktree list --porcelain | head -1 | awk '{print $2}')Atomic-write (tmp+rename) .project/security/audit-{YYYYMMDD-HHmm}.json:
{
"schemaVersion": 1,
"id": "{YYYYMMDD-HHmm}",
"startedAt": "{ISO 8601, now}",
"updatedAt": "{ISO 8601, now}",
"status": "running",
"phase": "PHASE 2",
"mainRoot": "{main_root}",
"scope": { "choice": "{scope}", "dir": null, "fileCount": 0 },
"stack": "{detected stack summary}",
"shipTriageRef": null,
"tooling": {},
"scanners": {},
"aggregate": {},
"plans": {},
"chosenStrategy": null,
"worktree": null
}Every later phase boundary patches updatedAt + phase (and its own fields) into this same file —
resolve via mainRoot from here on, never a relative .project/security/ path (PHASE 5 changes cwd
into a worktree where that path does not exist — see references/fix-implement.md § Worktree).
PHASE 2: Tooling scan
Todo: mark PHASE 1 →
completed, PHASE 2 →in_progress.
LLM pattern scanners (PHASE 2b) miss CVE data, malicious-package signals, and leaked secrets in git history. Supplement with OSS tooling. Read references/supply-chain.md for the full procedure (OSV-Scanner V2 + Semgrep CE + gitleaks detection, invocation, severity mapping).
Steps summarized:
- Detect lockfiles (
package-lock.json,yarn.lock, etc.). No lockfile → skip OSV with log (gitleaks still runs — it scans the repo, not lockfiles). - Run
osv-scanner --format=json scan source ./→.project/security/osv-report.json. Not installed + npm project → fallbacknpm audit --json --omit=dev. - Run
semgrep scan --config auto --json --quiet→.project/security/semgrep-report.json. Semgrep not installed → skip with log (not a blocker). - Run
gitleaks detect --report-format json --report-path .project/security/gitleaks-report.json(secrets in working tree + git history). Not installed → skip with log. - Tools not installed → log an installation hint, not a blocker. User can rerun after install.
Patch the audit state's tooling field with each tool's status (ran / skipped: "not installed" / fallback: "npm audit") and report paths. The actual finding-merge into PHASE 2b's scan results (OSV/npm-audit → A03; Semgrep per rule metadata.category; gitleaks → A04) happens in PHASE 3 — this script/tool output can only be read from the main chat, not from inside a Workflow sandbox.
Threshold: CRITICAL OSV vuln with fixed_version → automatically into the Minimal fix strategy (PHASE 4). Otherwise follow the normal strategy choice.
PHASE 2b: Parallel OWASP scan
Todo: mark PHASE 2 →
completed, PHASE 2b →in_progress. On a resume (§ PHASE 1 Step 0), OWASP_CONTEXT is not persisted in the audit state — re-derive it now via PHASE 1 Step 4 (project.json/project-context.json) before writing scanner prompts. On a fresh (non-resumed) run it is already in hand from Step 4. Read.claude/skills/dev-security/references/orchestration.md § 2and follow it: write the 10 scanner prompt files, launchsecurity-scan.js, patch the audit state. End the turn — no further tool calls until the task-notification arrives.
| Agent | Category | Risk | Focus |
| owasp-a01-scanner | Broken Access Control | CRITICAL | Missing authz on mutations/routes; IDOR via client-supplied IDs |
| owasp-a02-scanner | Security Misconfiguration | HIGH | Insecure defaults, headers, env exposure, verbose errors |
| owasp-a03-scanner | Supply Chain Failures | HIGH | Unpinned/vulnerable deps, untrusted script/CDN sources |
| owasp-a04-scanner | Cryptographic Failures | HIGH | Weak/missing hashing, secret exposure, premature data reveal |
| owasp-a05-scanner | Injection | CRITICAL | SQL/NoSQL/XSS/command/template injection, unvalidated input |
| owasp-a06-scanner | Insecure Design | MEDIUM | Abuse cases, missing rate limits, race conditions |
| owasp-a07-scanner | Authentication Failures | HIGH | Session/device binding, PIN/lockout robustness |
| owasp-a08-scanner | Data Integrity Failures | MEDIUM | Client-trusted state affecting scoring/results integrity |
| owasp-a09-scanner | Logging & Alerting Failures | MEDIUM | Missing audit trail on privileged/destructive actions |
| owasp-a10-scanner | Exceptional Conditions | MEDIUM | Malformed input handling, unhandled rejections, DoS via bad data |
Each agent receives: tech stack summary, file list (grouped by type), OWASP_CONTEXT (from PHASE 1 Step 4), project root path. Each agent returns structured output (schema-validated by the workflow): category score (/10), justification, positives, findings (file, line, severity, confidence, issue, fix, CWE), verdict.
On the task-notification, the workflow has already computed aggregate (weighted score, findings
at confidence ≥60%, severity counts, anti-fantasy suspicion) — continue to PHASE 3.
PHASE 3: Aggregation & Report
Todo: mark PHASE 2b →
completed, PHASE 3 →in_progress.
Persist first (orchestration.md § 2's "On return" step already writes scanners + aggregate
into the audit state).
No plan-mode entry here — this triage produces a report, not a reviewable proposal the user can
accept or reject (shared/PLAN-MODE.md § Wanneer plan mode): the "No, report only" branch below just
displays the report and stops, and "Yes" is a forward routing choice, not an approval gate. The
judgment work (tool-finding merge, anti-fantasy check, verdict) runs on the session's own Opus model
regardless — plan mode is no longer a model-routing device in this repo.
- Merge PHASE 2 tool findings into the scanner aggregate (only the main chat can read the tool
report files): OSV/npm-audit findings → A03; Semgrep findings → per rule
metadata.category; gitleaks findings → A04 (CRITICAL when the credential looks active, otherwise HIGH). OSV severity mapping: CRITICAL/HIGH/MODERATE/LOW → severity 1-to-1. - Check
aggregate.scannersFailed— non-empty → note which OWASP categories didn't return a result (mirrors PHASE 4'splannersFailedhandling) and surface it in the report below asCoverage: N/10 categories scanned — {codes} failed. The verdict is computed only from the categories that did return; never present it as full-coverage when it wasn't. - Fold in the ship-triage findings (only when PHASE 1 preloaded
shipTriageRef) — already-knownconfirmed[]items from the dev-ship handoff, deduped against anything the scanners rediscovered. If the relevant category's scanner re-verified the item as fixed (its own findings/verdict no longer show it) → report it as resolved, not as an open finding. Only count ashipTriageRefitem toward the open-findings tally when its scanner did not independently confirm a fix. - Anti-fantasy judgment:
aggregate.antiFantasySuspectflags 3+ scores of 9-10 — apply judgment on top of the mechanical flag: expect justification per high score, reconsider "would a pentester give these scores?" - Verdict: PASS (score ≥7.0, 0 CRITICAL findings) | NEEDS WORK (score <7.0 OR CRITICAL findings).
Second-opinion escalation (the consult agent is read-only, no plan mode needed either side): if (a) two sources conflict on the same finding (scanner vs PHASE 2 tool vs
shipTriageRef), or (b) ≥1 CRITICAL finding has confidence < 80%, or (c)antiFantasySuspectfired AND the verdict flips on judgment —Todo: Read
.claude/skills/shared/SECOND-OPINION.mdand follow it — the trigger auto-fires the consult (no confirm step) with INPUT = the audit state file + the disputed findings' cited source files, disputed findings inline as compact JSON (security row of § Brief contents). Apply the digest's per-finding verdicts to the report below (advisory — flips are shown, not silent), setsecondOpinionUsed.
Present consolidated report:
SECURITY AUDIT
Project: [name]
Tech Stack: [detected]
Files Scanned: [count]
{Coverage: N/10 categories scanned — {codes} failed — only shown when aggregate.scannersFailed is non-empty}
Overall Security Score: [X.X]/10
| Category | Score | Findings |
| -------------------------- | ----- | ---------- |
| A01 Broken Access Control | X/10 | N findings |
| A02 Security Misconfig | X/10 | N findings |
| ... | | |
Summary:
CRITICAL: [N] | HIGH: [N] | MEDIUM: [N] | LOW: [N]
TOP CRITICAL/HIGH FINDINGS:
1. [severity] [category] — [issue] — [file:line]
2. ...
(findings sharing one root cause/fix → group under a shared heading instead of listing flatly;
each finding still cites its own severity/category/file:line within the group)
Verdict: PASS (score ≥7.0, 0 CRITICAL findings) | NEEDS WORK (score <7.0 OR CRITICAL findings)
Second opinion: {consulted ({trigger}) — {n} finding verdict(s) revised | not triggered | unavailable}Explicit feature-arg auto-proceed — when PHASE 1 was invoked with an explicit {feature}
arg, skip the modal: proceed straight to "Yes, generate fix plans" (log: Next step: fix-plannen
genereren (auto, feature-arg gegeven)), then Read
.claude/skills/dev-security/references/fix-implement.md and continue there (PHASE 4).
No feature-arg (full-codebase run) → AskUserQuestion:
- header: "Next step"
- question: "Do you want to generate fix plans for the found issues?"
- options:
- "Yes, generate fix plans (Recommended)" — 3 parallel fix strategies
- "No, report only" — Stop here with the audit report
- multiSelect: false
"No" → Patch audit state status: "complete", phase: "PHASE 3". Show the report.
Todo: mark PHASE 3 →
completed. Leave PHASE 4/5pending— "No, report only" ends the run here by design, not on a failure, so there is nothing to mark done or in-progress for them. Apply the Next-Step Clipboard Offer (binary Ja/Nee) — read.claude/skills/shared/NEXT-STEP-OFFER.md. Recommended command:/dev-ship {feature}→ apply security hardening as a refactor step.
"Yes" → Read .claude/skills/dev-security/references/fix-implement.md and continue there
(PHASE 4) — its own PHASE 4b Workflow launch needs no plan-mode exit anymore, since PHASE 3 never
entered plan mode.
PHASE 4 & PHASE 5
Todo: Read
.claude/skills/dev-security/references/fix-implement.mdand follow it — it owns the fix-plan fan-out, the strategy-selection plan-mode gate, the worktree'd implementation, and the finalize offer.
Best Practices
Language
Follow the Language Policy in CLAUDE.md.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

