agentleFS
rcdelfinrcdelfin/agentkit/skills/software-development/security-audit-light/SKILL.md

security-audit-light

Skill2 starsChanged 3 months agoMITView on GitHub

Perform a PR-scoped security audit on a small to medium code change (1-20 files, additive endpoint, schema change, refactor). Produces a structured findings table with confidence scores, no false positives, and a clean verdict. Trigger only when the user explicitly asks for a "security audit", "security review", "vulnerability check", "is this safe to ship", or "OWASP check" of recent changes. NOT for greenfield threat modeling, full-codebase reviews, or infrastructure audits — those need heavier tooling. NOT for proactive scanning while writing code.

The file

We split this skill into the rules it gives an agent

6 rules. About 0 are common, 5 are distinctive, and 1 is very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈5

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 1

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Read top-level config files to confirm framework, then declare scope explicitly:

    line 27
  2. Very specific:

    Framework-meta rule: when the symbol is generated by ORM/framework metaclass (Eloquent scope, Django Meta, Rails has_many, Laravel …

    line 66
  3. Distinctive:

    If the user says they shipped a fix, re-read the changed file and re-run steps 2-5 scoped to the fix.

    line 106
  4. Distinctive:

    "No findings" without coverage statement: if your attack surface census shows zero rows, you didn't audit — you just said "looks safe".

    line 110
  5. Distinctive:

    Reusing scope from a previous audit: if the user asks for a NEW audit, do not reuse conclusions from a previous one without re-verifying.

    line 112
  6. Distinctive:

    When the audit is clean, keep the output short.

    line 156

≈ “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.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Security Audit (Light)

PR-scoped security audit distilled from CSO's methodology. Optimized for additive endpoints, schema changes, small refactors. Single-prong — read the diff, verify each finding end-to-end, output a verdict. No subagent fan-out, no infrastructure passes, no telemetry.

When to use

  • User says "security audit", "security review", "OWASP check", "is this safe", "anything fishy?"
  • Scope is the current branch / latest uncommitted changes (1-20 files)
  • Stack is one of: PHP/Laravel, Python/Django/FastAPI, Node/Express/Nest, Ruby/Rails, Go/Gin, Java/Spring Boot, Rust/Axum

When NOT to use

  • Greenfield (no code yet) → use systematic-debugging or another skill
  • User asks for full codebase audit → this skill is PR-scoped by design
  • User wants proactive scanning while writing code → defer to security-best-practices
  • Audit depends on infrastructure (CI/CD, deploy pipeline, secrets manager) → out of scope

Procedure

Step 1 — Detect stack + scope (30 seconds)

Read top-level config files to confirm framework, then declare scope explicitly:

FieldSourceExample
Stackcomposer.json, package.json, pyproject.toml, etc.Laravel 12 / PHP 8.4
Scopegit diff --stat <baseline>..HEAD5 files, 202 insertions
Branchgit branch --show-currentfeat/GYMED-793
Baseline SHAgit rev-parse --short HEAD~1 (or merge-base)79d68ef

State scope in the output: "Auditing 5 files / 202 insertions on feat/X since <sha>."

Step 2 — Attack surface census (1 minute)

Build a tiny table covering what an attacker can touch. For each row, name the file:line or write none.

ATTACK SURFACE CENSUS
  AuthN entry points:      N (e.g. auth:api middleware — routes/api.php:25)
  Authorization gates:     N (e.g. abort_unless isProfessional — DashboardController.php:89)
  Cross-tenant scoping:    N (e.g. sessionsForProfessionalStudents — Service.php:140)
  User-supplied inputs:    N (e.g. filter[status], pain_level, rpe)
  Output resource fields:  N (e.g. DashboardSessionPreviewResource)
  Storage mutation paths:  N (e.g. markAsReviewed, store, update)
  Pagination cursors:      N (e.g. cursorPaginate(15))
  Sensitive field loads:   N (e.g. user selects [..., email, ...])

This forces you to declare coverage before claiming "clean". If a row is none, you've just decided it's out of scope — make that decision visible.

Step 3 — Pre-emit verification gate (the "1539 rule")

For every potential finding, BEFORE writing it:

  1. Quote the verbatim code that motivates it with file:line. Not a paraphrase — the exact text.
  2. Trace it end-to-end: from input (Request / user / external caller) to output (Query / Response / file). Confirm the path exists, not just the pattern.
  3. Confirm the mitigating code exists by quoting it (e.g. the validator rule, the authorization check, the scope-bypass).

If you cannot quote the motivating line, drop the finding's confidence to 4-5 (suppressed from main report, go to appendix only). Do not invent confidence to pass the gate.

Framework-meta rule: when the symbol is generated by ORM/framework metaclass (Eloquent scope, Django Meta, Rails has_many, Laravel withoutGlobalScope), quote the meta-construct or migration — don't expect the literal name in the class body.

Step 4 — Confidence calibration (1-10)

ScoreMeaningDisplay
9-10Verified by reading specific code, concrete exploit demonstratedMain report
7-8High confidence, very likely correctMain report
5-6Could be FP, verify with authorMain report with caveat
3-4Suspicious but possibly fineSuppressed — appendix only
1-2SpeculationOnly if severity is P0

Step 5 — Output format

Finding format:

[Px] (confidence: N/10) file:line — one-sentence description

Severity scale (priority = exploitability × blast radius):

CodeMeaning
P0Critical, ship-blocker, immediate exploit
P1High, ship after fix
P2Medium, plan a fix
P3Low, opportunistic / hardening
P4+Cosmetic / advisory

Final structure:

  1. Scope (1 line): branch, commit baseline, files changed
  2. Stack (1 line)
  3. Attack surface census (small table)
  4. Trust boundaries re-verified (table — "no new findings" rows OK)
  5. Findings (table: [Px] (N/10) file:line — description) — empty table if clean
  6. Verdict: APPROVED / APPROVED WITH NITS / BLOCKED with one-line reason

Step 6 — Re-audit if anything changes

If the user says they shipped a fix, re-read the changed file and re-run steps 2-5 scoped to the fix. Do NOT just accept "fixed it" — verify end-to-end the same way you verified the original finding.

Pitfalls

  • "No findings" without coverage statement: if your attack surface census shows zero rows, you didn't audit — you just said "looks safe". Always emit the census, even if every row is "none".
  • Pattern-match FPs (the FP class CSO calls "1539"): "field X doesn't exist" requires quoting the model body; "dict.get() might be None" requires quoting the dict init. If you find yourself writing "this could be a problem if X", stop and go read the X.
  • Reusing scope from a previous audit: if the user asks for a NEW audit, do not reuse conclusions from a previous one without re-verifying. Each audit is its own evidence chain.
  • Severity inflation: a missing CSRF token on an internal admin tool is not P0. Calibrate by exploitability × blast radius, not by vibes.
  • Skipping the user-supplied-input trace: most security bugs in PRs are at the input boundary (no validation, wrong scope, wrong auth). Always trace each query/body parameter from Request to Eloquent / QueryBuilder / fetch.
  • Listing what you DIDN'T audit as if it were clean: "no SQL injection found" is a claim. State the scope ("did not audit migrations", "did not audit infrastructure") separately.

Verification steps

  • Scope declared in opening line
  • Attack surface census has ≥5 rows, each with file:line or explicit "none"
  • Every finding quotes its motivating code line(s)
  • Every finding has a confidence 1-10 score
  • Findings at confidence ≤4 are in appendix, not main report
  • Final verdict is one of: APPROVED / APPROVED WITH NITS / BLOCKED
  • Findings count + verdict fit on one screen for clean audits, or fit on one page for noisy ones
  • Did-not-audit scope is stated separately from clean findings

Output template (copy-paste starter)

## Security audit — <branch> / <baseline-sha> → <head-sha>

**Stack**: <framework> <version>
**Scope**: <N> files, <N> insertions on `<branch>` since `<sha>`
**Method**: pre-emit verification gate + 1-10 confidence

### Attack surface census
| Boundary | Where | File:line |
|---|---|---|
| AuthN | <gating middleware/group> | <file>:<line> |
| AuthZ | <gate> | <file>:<line> |
| Cross-tenant scoping | <helper> | <file>:<line> |
| User-supplied inputs | <list, e.g. filter[status], page cursor> | <file>:<line> |
| Output resource | <resource class> | <file>:<line> |
| Sensitive field loads | <list, e.g. user selects> | <file>:<line> |

### Findings
| # | Finding | Severity | Confidence | Evidence |
|---|---|---|---|---|
| — | (none) | — | — | — |

### Verdict
**APPROVED** — <one-line summary of why, e.g. "additive endpoint reuses pre-audited scope chain; filter input whitelisted; no PII leakage in response.">

When the audit is clean, keep the output short. Length scales with findings, not with repo size.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

Reviews can't be read right now.

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.