mcpbeat Sign in

Security Scan Skill for Claude

Use when automated scanners drive a security sweep of a repo or app — SAST, dependency/lockfile CVEs, secrets in the tree or git history, IaC misconfig — and the raw output has to become one deduped, exploitability-ranked report CI can gate on. NOT threat-modeling, OWASP design reasoning, or hand-authoring the fix (that is `secure-coding`).

7k tokens
context cost
the whole folder, loaded on every use
6
files
ships runnable scripts
0
copies elsewhere
how many repositories repackaged it
105
stars on the repo
on the repository, not the skill itself

Install

one command, takes just this skill from the repository
npx skills add https://github.com/ericrisco/rsc-harness --skill security-scan

What comes with it

16 168 bytes besides the instruction
evals/README.md
evals/cases.yaml
references/tools.md
references/triage.md
scripts/verify.sh

The instruction itself

13 sections, as written by the author

Security scan — orchestrate scanners, triage the noise, emit a gate

A machine-first vulnerability sweep. Point automated scanners at a codebase,

collect SARIF/JSON, then do the work that has actual value: dedupe cross-tool

overlap, rank by exploitability, and emit one gate artifact CI can act on. The

finding comes from a tool run, not a hunch — if you are reasoning about a

design or hand-writing a fix, that is secure-coding,

not this skill.

Your job is orchestration + triage: every finding traces to a scanner run with a

ruleId and a source location, so the output is reproducible. Not eyeballing

code, not authoring patches.

Read-only by default. Scan, triage, report. Apply fixes (version bumps,

rotation, .gitignore edits) only when the user asks — a security sweep that

silently mutates the tree destroys the evidence and the trust.

Pin and verify your scanners. Exact versions, verified checksums/SHAs, never

@latest GitHub Actions. In March 2026 Trivy was supply-chain compromised

malicious releases v0.69.4/0.69.5/0.69.6 and a hijacked

aquasecurity/trivy-action exfiltrated CI secrets. Your scanner runs with repo +

CI-secret access; an unpinned scanner is itself the attack surface.

Scan classes and tool selection

Four classes: SAST (injection, XSS, path traversal in *first-party* code),

SCA / deps (known CVEs in dependency manifests + lockfiles), Secrets

(credentials in the tree or git history), Misconfig / IaC (Dockerfile,

k8s, Terraform, exposed config). Pick tools by what is in the repo. This is the

real branch point — match the tool to the manifest, do not run everything

everywhere.

| Repo contains | SAST | SCA | Secrets | Misconfig |

|---|---|---|---|---|

| Node (package-lock.json/pnpm-lock.yaml) | Semgrep | osv-scanner + npm audit (fast) | gitleaks → TruffleHog | Trivy |

| Python (poetry.lock/requirements.txt) | Semgrep | osv-scanner + pip-audit (fast) | gitleaks → TruffleHog | Trivy |

| Go (go.mod/go.sum) | Semgrep | osv-scanner (+ govulncheck for reachability) | gitleaks | Trivy |

| Containers (Dockerfile, images) | — | Trivy fs/image | Trivy --scanners secret | Trivy config |

| IaC (Terraform/k8s/Helm) | Semgrep (IaC rules) | — | gitleaks | Trivy config, Semgrep rulesets |

| Monorepo (mixed) | Semgrep auto | osv-scanner (multi-ecosystem) | gitleaks → TruffleHog | Trivy |

Full install (pinned), flag matrix, and suppression syntax: references/tools.md.

Run recipes

All recipes emit SARIF (or JSON you normalize to it) — a common schema is what

lets you merge four tools, dedupe, and feed one artifact into CI instead of four

incompatible logs. Pin the version shown; the placeholders below mark where

to lock an exact tag/digest.

SAST — Semgrep

Free OSS edition (latest 1.164.0, 2026-05-27): 30+ languages, ~2,000 community

rules. SCA + Secrets rulesets are gated behind the hosted platform — use the

dedicated tools below for those, not Semgrep.

# Pin via the CLI version, not @latest. OWASP ruleset, SARIF out.
semgrep scan --config p/owasp-top-ten --sarif --output sast.sarif .
# Broader local sweep (community rules), no telemetry:
semgrep scan --config auto --sarif --output sast.sarif --metrics off .

SCA — osv-scanner (primary), native auditors (fast pass)

osv-scanner (OpenSSF/Google) checks lockfiles against OSV.dev across ecosystems

and catches transitive CVEs the native auditors miss. Run native first for

speed, osv-scanner for coverage — never native alone.

# Primary: lockfile-aware, multi-ecosystem, SARIF.
osv-scanner scan source --format sarif --output sca.sarif .
# Fast first pass (ecosystem-native, weaker on transitive):
npm audit --omit=dev --audit-level=high --json > npm-audit.json   # Node
pip-audit --format json --output pip-audit.json                   # Python

Secrets — gitleaks (tree + history), TruffleHog (verified)

gitleaks (~150+ patterns, sub-second on diffs) is the pre-commit/CI workhorse.

TruffleHog (800+ types) adds live credential verification — it auth-tests a

hit to tell a real leaked key from a sample. Scan history, not just the tree:

a key deleted in HEAD is still in the pack files and still rotatable.

# gitleaks: redacted SARIF over the working tree AND full git history.
gitleaks detect --redact --report-format sarif --report-path secrets.sarif
# TruffleHog: only verified (live) secrets across history.
trufflehog git file://. --only-verified --json > trufflehog.json

Misconfig / IaC — Trivy (PINNED — see the caveat above)

Trivy scans filesystems, images, and IaC and finds transitive CVEs npm audit

misses.

# Pin the EXACT version (NOT v0.69.4/.5/.6 — those were the malicious releases).
# Verify the checksum/cosign signature before first use. See references/tools.md.
trivy fs --scanners vuln,secret,misconfig --format sarif --output trivy.sarif .

Triage — turn noise into a ranked report

The deliverable is not the four SARIF files. It is a deduped, ranked report.

  • Merge + dedupe. Cross-tool overlap is real (osv-scanner and Trivy both

flag the same CVE; gitleaks and TruffleHog both flag the same key). Key on

(class, normalized-id, path, line) and keep the richest record — prefer the

one with verification (TruffleHog) or reachability (govulncheck).

  • Normalize severity. SARIF level and tool-native severities disagree;

map them all to one critical/high/medium/low scale (references/triage.md).

  • Rank by exploitability, not by count. A finding scores higher when it is

reachable (called, not just present) + exposed (on an untrusted path)

+ a sensitive sink (auth, money, PII, RCE). A verified live secret or a

reachable RCE CVE outranks a theoretical lib finding behind a feature flag.

  • Suppress with a written justification, never a blanket ignore. Each

suppression records *who, why, and an expiry* — not a silent .semgrepignore

that hides the next real bug too.

BAD  — dump 412 raw findings from four tools, sorted alphabetically, no ranking.
GOOD — 3 unsuppressed criticals first:
       1. [secrets] VERIFIED live Stripe sk_live_… in config/.env (history) → ROTATE NOW
       2. [sca] CVE-2024-… lodash 4.17.20 transitive, reachable in src/api/parse.ts → bump 4.17.21
       3. [sast] SQL built from req.query in routes/search.js:48 → parameterize
       + 7 mediums summarized, + 18 suppressed (each with justification + expiry).

Full ranking rubric, dedupe keying, and severity-normalization map:

references/triage.md.

The gate artifact

Emit one security-scan-report.json — the machine-checkable contract CI gates on.

{
  "schemaVersion": "1.0",
  "scannedAt": "2026-06-02T10:00:00Z",
  "target": ".",
  "tools": [{ "name": "osv-scanner", "version": "2.0.2" }],
  "summary": { "critical": 1, "high": 2, "medium": 7, "low": 14, "suppressed": 18 },
  "findings": [
    {
      "class": "sca",
      "ruleId": "CVE-2024-XXXXX",
      "path": "package-lock.json",
      "line": 0,
      "severity": "critical",
      "status": "open",
      "tool": "osv-scanner",
      "exploitability": "reachable",
      "title": "Prototype pollution in lodash <4.17.21"
    }
  ]
}
  • status is one of open | suppressed | fixed; severity one of

critical | high | medium | low. Schema in full: references/triage.md.

  • Gate rule: any open finding at critical (and, on a strict gate, high)

→ fail. suppressed never fails. scripts/verify.sh enforces exactly this and

exits 0 on a clean/empty report (no false failure).

CI wiring (brief)

  • Pin actions to a full commit SHA, not a tag, never @latest — the hijacked

aquasecurity/trivy-action was pulled by tag.

# .github/workflows/security-scan.yml — pin the SHA, verify before bumping.
- uses: aquasecurity/trivy-action@<full-40-char-sha>  # NEVER @latest / @master
  with: { scan-type: fs, format: sarif, output: trivy.sarif }
- run: ./scripts/verify.sh   # gate on security-scan-report.json
  • Upload SARIF to code scanning; gate the merge on verify.sh, not on a human

reading logs. See github-actions for the

pipeline shell and verify for the broader green gate

this feeds.

Anti-patterns

| Anti-pattern | Do instead |

|---|---|

| Pulling aquasecurity/trivy-action@latest because it is the official action | March 2026: a hijacked tag stole CI secrets. Pin a full SHA, verify provenance. |

| Treating every scanner finding as a bug to fix | Most are noise. Rank by reachable + exposed + sensitive sink; report the few that matter. |

| Calling the repo clean after scanning only the working tree | History holds the deleted keys. Scan git history; a removed-in-HEAD key is still leaked and live. |

| Declaring deps fine because npm audit is clean | Native auditors miss transitive CVEs. Run osv-scanner/Trivy too; native is the fast pass, not the only pass. |

| Committing a blanket .semgrepignore to quiet CI | A blanket ignore hides the next real bug. Suppress per-finding with a written justification + expiry. |

| Deleting a verified key from the file and moving on | Deleting ≠ safe. Rotate the credential first, then scrub history. The committed value is already compromised. |

| Taking the SARIF level as the severity | Tools disagree. Normalize to one scale before you rank or gate. |

| Dumping all four tool outputs in the PR for the reviewer to sort | The reviewer won't. Merge, dedupe, rank, and emit one report. |

| Letting the scan auto-fix the deps it finds | Read-only by default. Propose bumps; apply only when asked — never mutate during a sweep. |

Project grounding (02-DOCS + CLAUDE.md)

In a project with a 02-DOCS/ layer (the harness

Karpathy wiki), record the scanner choices, pinned versions, gate thresholds, and

any accepted-risk suppressions in 02-DOCS/wiki/stack/security-scan.md, and index

it in 02-DOCS/wiki/index.md (the Knowledge map; root CLAUDE.md keeps only a short

pointer to it). Read it first on every run so the next agent inherits the pinned

tools and thresholds instead of re-deriving them. No 02-DOCS/? Skip silently.

Conventions are recorded, not gated — never block the scan on this.

See Also

Reviewing a diff rather than scanning a repo: code-review

for correctness and quality, review for adversarial review

against a spec.

How to use it

Copy the folder

Take ericrisco/security-scan from the repository into ~/.claude/skills for personal use, or into .claude/skills inside a project.

Check the name does not clash

The agent identifies a skill by the name field in its header. Two skills with the same name cannot sit side by side — one of them will be ignored.