Skip to main content

vuln-scanner

Audit trending repos for real security vulnerabilities and disclose responsibly - scan and route findings (PVR / dependency PR), re-submit queued advisories, and send armed email disclosures

Ir para a instalação

Informações da origem

Repositório
aeonfun/aeon
Última atividade na origem
16 de setembro de 2026 às 14:14
Idioma detectado do SKILL.md
inglês
Estrelas
738
Forks
265

Opções de instalação

Por padrão, está selecionado o prompt que primeiro revisa a origem. Você pode mudar para um comando direto ou baixar uma cópia local.

Revise os arquivos de origem

Leia o SKILL.md e os arquivos complementares exibidos pelo SkillsMP antes de decidir se vai instalar.

Explorador de arquivos
2 arquivos

Exibindo SKILL.md

SKILL.md
Instruções da origem · Visualização somente leitura
name
vuln-scanner
description
Audit trending repos for real security vulnerabilities and disclose responsibly - scan and route findings (PVR / dependency PR), re-submit queued advisories, and send armed email disclosures
metadata
{"title":"Vuln Scanner","category":"dev","var":"","tags":["dev","security","meta"],"depends_on":["github-trending"],"requires":["GH_GLOBAL?","RESEND_API_KEY?","RESEND_FROM?","RESEND_REPLY_TO?"]}
<!-- autoresearch: variation B — responsible-disclosure-first: private reports for code vulns, public PRs only for already-disclosed dep CVEs --> > **${var}** — Action selector, shaped `[<action>][:<owner/repo>]`. Empty or a bare `owner/repo` → **scan** arm (audit that repo, or auto-select a trending one). `resubmit` / `resubmit:owner/repo` → **re-submit** arm (probe the security watchlist for repos that just enabled PVR and submit any queued advisory). `disclose` / `email` → **disclose** arm (queue armed out-of-band email disclosures for sending). Examples: > - `` → scan, auto-select from trending > - `openai/whisper` → scan `openai/whisper` > - `resubmit` → probe the whole watchlist and re-submit what flipped > - `resubmit:vercel/next.js` → probe just that repo (one-off) > - `disclose` (alias `email`) → arm & queue eligible disclosure emails > - `poc-smoke` → exercise the PoC gate against a benign real Base fork (no audit or disclosure) > - `riva:owner/repo` → scan with the Riva research kernel (shadow/proposal only) Today is ${today}. Read `memory/MEMORY.md` and the last 30 days of `memory/logs/` before starting. ## Why this skill exists This is the **write / action arm of the vuln-disclosure loop** — one skill covering the full responsible-disclosure lifecycle: - **Scan** — a security scanner that dumps unpatched vulnerabilities into public PRs is a zero-day publisher, not a helper. This skill matches industry practice: **Private Vulnerability Reporting (PVR) for code flaws, public PRs only for dependency CVEs that are already public**. Bad disclosure burns credibility and puts users at risk. - **Re-submit** — when a scan finds a HIGH/CRITICAL issue in a repo with no PVR, no `SECURITY.md`, and no reachable contact, it has no safe channel — so it logs the finding as `"channel": "skipped"` in `memory/vuln-scanned.json` and stages a watchlist row. Without a weekly probe those findings silently age until the responsible-disclosure window closes. The re-submit arm closes that loop. - **Disclose** — when the only responsible path is a private email to the maintainer, drafts sit in `memory/pending-disclosures/` with `status: pending-operator-send`, waiting for a human. The disclose arm finds drafts **explicitly armed for auto-send**, composes the email, and **sends it in-run** (Resend via `./secretcurl`) behind a set of fail-closed caps — the send is the arm's final action. ## Dispatch — parse `${var}`, then run one arm Parse the selector once, then jump to the matching arm below: ```bash SEL="${var}" # the raw selector ACTION="${SEL%%:*}" # token before ':' (or the whole thing) TARGET="${SEL#*:}"; [ "$TARGET" = "$SEL" ] && TARGET="" # token after ':' (empty if no ':') case "$ACTION" in resubmit|watchlist|pvr) ARM="resubmit" ;; # → Arm B disclose|email) ARM="disclose" ;; # → Arm C poc-smoke|verify-gate) ARM="poc-smoke" ;; # → Arm D riva|research) ARM="scan"; KERNEL="riva" ;; # → Arm A, Riva kernel shadow|compare) ARM="scan"; KERNEL="shadow" ;; # → Arm A, private comparison ""|scan) ARM="scan" ;; # → Arm A (auto-select if TARGET empty) */*) ARM="scan"; TARGET="$SEL" ;; # bare owner/repo → scan that repo *) ARM="scan" ;; # unknown → default to scan esac # Legacy remains the safe default while Riva is evaluated. `shadow` produces a # private comparison artifact; only an explicit `riva` selector or a reviewed # environment override selects it for a scan. Neither mode changes disclosure # authority or bypasses A4/A4.5. KERNEL="${KERNEL:-${VULN_RESEARCH_KERNEL:-legacy}}" case "$KERNEL" in legacy|shadow|riva) ;; *) KERNEL="legacy" ;; esac ``` - `ARM=scan` → **Arm A — SCAN** (target = `$TARGET`, or auto-select if empty). - `ARM=resubmit` → **Arm B — RE-SUBMIT** (probe `$TARGET` if set, else the whole watchlist). - `ARM=disclose` → **Arm C — DISCLOSE** (queue armed email drafts). - `ARM=poc-smoke` → **Arm D — PoC GATE SMOKE** (benign live-fork verification only). Each arm is independently executable. The operational arms share the same GitHub token and the same `memory/` state (`vuln-scanned.json`, `security-watchlist.md`, `pending-disclosures/`, `email-log.json`) — that shared state is exactly how the arms hand off to each other. The smoke arm does not read or modify that state. --- ## Arm A — SCAN Find one trending repo, run purpose-built scanners (not raw grep), triage to real exploitable findings, and route each finding to the correct disclosure channel — PVR, `SECURITY.md` contact, or dependency-bump PR. ### A1. Pick a target If `$TARGET` is set, use it. Otherwise: ```bash # Prefer chained output from github-trending skill CANDS="" if [ -s output/.chains/github-trending.md ]; then # Parse owner/repo targets. Accept BOTH the markdown form [owner/repo](url) and a # bare github.com/owner/repo permalink (a feeder degraded under read-only can emit # the latter). A repo name with no owner is NOT a candidate. Pick the first CANDS # entry that matches the criteria below. CANDS=$(grep -oE '\[[^]]+/[^]]+\]\(https?://[^)]+\)|https?://github\.com/[^/ )]+/[^/ )]+' output/.chains/github-trending.md \ | sed -E 's#.*github\.com/##; s#\).*##; s#^\[##; s#\].*##' | grep -E '^[^/ ]+/[^/ ]+$' | sort -u) fi # If the feed was absent OR present-but-unparseable (zero owner/repo lines, e.g. a # header-only / prose-only notify body), do NOT stop here - that starves the scan. if [ -z "$CANDS" ]; then # Shadow runs have no GitHub credentials by design. A bare shadow selector # may consume the chained trending output above, but otherwise must fail # closed and be retried as shadow:owner/repo. if [ "$KERNEL" = shadow ]; then echo "VULN_SCANNER_SKIPPED shadow-target-required: use shadow:owner/repo or provide github-trending chain output" exit 0 else gh api "search/repositories?q=created:>$(date -u -d '14 days ago' +%Y-%m-%d)&sort=stars&order=desc&per_page=25" \ --jq '.items[] | select(.fork==false) | select(.stargazers_count>=50) | {full_name, language, description, security_and_analysis}' fi fi ``` Selection criteria: - Language you can reason about (JS/TS, Python, Go, Rust, Solidity) - ≥50 stars, not a fork, active in last 6 months - Handles untrusted input: auth, crypto, network, file I/O, templating - **Skip** if scanned in last 30 days (grep `memory/logs/` for the repo name) - **Skip** deliberately vulnerable teaching repos (DVWA, juice-shop, webgoat, vulnerable-*, *-ctf, hackme-*) - **Skip** repos with no `SECURITY.md` AND `security_and_analysis.private_vulnerability_reporting.status != "enabled"` — you have no safe channel to report code flaws (you can still run a dep-scan and skip code audit; see step A5) ### A2. Fork and clone ```bash REPO="owner/repo" if [ "$KERNEL" = shadow ]; then git clone --depth 200 --quiet "https://github.com/${REPO}.git" else gh repo fork "$REPO" --clone --default-branch-only -- --depth 200 --quiet fi cd "$(basename "$REPO")" ``` ### A3. Run purpose-built scanners Raw grep produces too many false positives. Use tools with dataflow reachability and verified-secret matching. Stage the scanners **in-run** into `/tmp/bin` (see the install preamble below). The network is open, but `pip install` / a curl-piped-to-shell install / `tar` are **not** on the in-run capability allowlist — use the ones that are: `python3 -m pip install …` for the Python tools (semgrep, slither) and `curl -o … && chmod +x` for the Go binaries (osv-scanner, trufflehog). Put `/tmp/bin` on `PATH` and invoke each tool by **bare name** — the bare names (`semgrep`, `trufflehog`, `osv-scanner`, `slither`) are exactly what the capability allowlist (`scripts/skill_mode.sh`) grants, so `claude -p` is permitted to execute them. If a binary is missing, log `VULN_SCANNER_SKIPPED` and continue (it records `fail` in `sources.txt` below) — never abort the whole run for one tool. ```bash mkdir -p /tmp/vuln-scan /tmp/bin export PATH="/tmp/bin:$PATH" # Stage the scanners IN-RUN, best-effort, using ONLY allow-listed commands (network is # open, but `pip install` / a curl-piped-to-shell install / `tar` are NOT allow-listed — `python3 -m pip`, # `curl -o`, `chmod`, `npm`/`npx`, `node` ARE). Wrap each in `|| true`; any tool that fails # to stage is skipped by the `command -v` guards below (records fail), never fatal: python3 -m pip install --quiet --disable-pip-version-check semgrep slither-analyzer 2>/dev/null || true curl -sSL -o /tmp/bin/osv-scanner "https://github.com/google/osv-scanner/releases/latest/download/osv-scanner_linux_amd64" 2>/dev/null && chmod +x /tmp/bin/osv-scanner || true # trufflehog: stage its release binary the same way if a raw asset exists; else it's skipped below. # --- SAST: Semgrep OSS --- if command -v semgrep >/dev/null 2>&1; then semgrep --config=p/security-audit --config=p/owasp-top-ten --config=p/secrets \ --severity=ERROR --severity=WARNING --json --quiet --timeout=300 \ --exclude=test --exclude=tests --exclude=__tests__ --exclude=spec --exclude=specs \ --exclude=fixtures --exclude=examples --exclude=example --exclude=demo \ --exclude=vendor --exclude=node_modules --exclude=dist --exclude=build --exclude=.next \ -o /tmp/vuln-scan/semgrep.json . 2>/dev/null || true else echo "VULN_SCANNER_SKIPPED: semgrep not available" fi # --- Secrets: TruffleHog (only-verified = actually authenticates) --- if command -v trufflehog >/dev/null 2>&1; then # BOTH passes are bounded. Run these verbatim; if you invoke trufflehog (or any # scanner) yourself, it still needs the `timeout 300` wrapper and must not be # backgrounded with `&` — a scan still running when you write the report is a # scan you did not finish, and a one-shot workflow_dispatch run cannot resume it. TRUFFLEHOG_RC=0 timeout 300 trufflehog filesystem . --only-verified --json \ > /tmp/vuln-scan/trufflehog.json 2>/dev/null || TRUFFLEHOG_RC=$? [ "$TRUFFLEHOG_RC" = 124 ] && echo "VULN_SCANNER_TIMEOUT: trufflehog filesystem scan exceeded 300s on a very large tree — recorded as fail, not retried, not left unfinished" # Also scan full git history for secrets — BOUNDED. An unbounded `trufflehog git` # walks every commit's every tree, and a large packed history (measured: 200 # commits / ~369MB on one real run) can eat the whole turn budget by itself, # with nothing to show it happened until the run reports "success" anyway # having produced no report at all. `timeout` turns that silent budget-burn # into an ordinary, honestly-recorded `fail` — same as an install failure, # never a reason to write a "still running, will resume" placeholder as the # final output. There is no resume: a workflow_dispatch run is one shot, and # a note promising to pick back up later is not truthful about what a single # run can actually do. TRUFFLEHOG_GIT_RC=0 timeout 300 trufflehog git file://. --only-verified --json \ > /tmp/vuln-scan/trufflehog-git.json 2>/dev/null || TRUFFLEHOG_GIT_RC=$? [ "$TRUFFLEHOG_GIT_RC" = 124 ] && echo "VULN_SCANNER_TIMEOUT: trufflehog git history scan exceeded 300s on a large packed history — recorded as fail, not retried, not left unfinished" else echo "VULN_SCANNER_SKIPPED: trufflehog not available" fi # --- Dependencies: osv-scanner (unified CVE DB across ecosystems) --- # osv-scanner v2 (what `releases/latest` now installs, 2.4.x) moved scanning under the # `scan source` subcommand. The v1 bare form (`osv-scanner --recursive .`) still works on # 2.x, so try v2 first and fall back to v1 only if v2 wrote NOTHING (keyed on emptiness, # NOT exit code - osv exits 1 when it FINDS vulns, which must not read as a syntax error). # `--no-ignore` is REQUIRED: v2 `scan source` respects .gitignore by default, so a target # repo that gitignores its (committed) lockfile - common for libraries/tools - yields the # misleading "No package sources found" (exit 128) and zero dependency coverage. A shipped- # but-gitignored lockfile still describes real deps, so a security scan must read it. It is # a no-op when lockfiles are tracked. if command -v osv-scanner >/dev/null 2>&1; then osv-scanner scan source --recursive --no-ignore --format=json . > /tmp/vuln-scan/osv.json 2>/dev/null; OSV_RC=$? [ -s /tmp/vuln-scan/osv.json ] || { osv-scanner --format=json --recursive --no-ignore . > /tmp/vuln-scan/osv.json 2>/dev/null; OSV_RC=$?; } # Classify: exit 128 = "No package sources found" = the repo has no lockfiles/manifests # to scan. That is a clean N/A (nothing to do), NOT a scan failure - osv writes an EMPTY # file in that case, so `[ -s ]` alone would mislabel it `fail`. Distinguish the states: if [ -s /tmp/vuln-scan/osv.json ]; then OSV_STATUS=ok # ran; results present (0 or N dep CVEs) elif [ "${OSV_RC:-}" = 128 ]; then OSV_STATUS=none # ran; no dependency lockfiles -> n/a else OSV_STATUS=fail; fi # genuine tool error else OSV_STATUS=skipped echo "VULN_SCANNER_SKIPPED: osv-scanner not available" fi # --- Smart-contract scan (if Solidity present) --- if ls **/*.sol >/dev/null 2>&1 && command -v slither >/dev/null 2>&1; then slither . --json /tmp/vuln-scan/slither.json --exclude-informational --exclude-low 2>/dev/null || true fi # Record what succeeded (empty output ≠ clean, could be tool failure) echo "semgrep=$([ -s /tmp/vuln-scan/semgrep.json ] && echo ok || echo fail)" > /tmp/vuln-scan/sources.txt # TruffleHog JSON is finding-only: an exit-0 empty stream is a clean scan. if [ "${TRUFFLEHOG_RC:-1}" = 124 ]; then echo "trufflehog=timeout" >> /tmp/vuln-scan/sources.txt else
Ver no GitHub
Este SKILL.md e muito grande, entao o SkillsMP mostra aqui apenas a primeira secao. Ver no GitHub