跳到主要内容
知仓学习社ZHICANG

vuln-scan

Systematic vulnerability scan across injection, auth, data exposure, and dependencies — traced by reading code, not grepping for keywords. Use when …

不碰外部(只输出文字)无严重或高危命中hashgraph-online/awesome-codex-plugins

它会碰到什么

扫了多少1 个文本文件,8 KB
它会碰到什么不碰外部(只输出文字)
命中总数0 处
命中统计严重 0 · 高 0 · 中 0 · 低 0

这一栏是扫描器报的事实,不是结论。命中多不等于有毒(安全工具、规则库、示例脚本本来就会包含危险写法),命中少也不等于干净。它和你手上的凭据、文件、网络有什么关系,需要你自己看。

技能内容

Vuln Scan — Systematic Vulnerability Scanner

Iron Law

Code you haven't traced from input to sink has vulnerabilities you haven't found. A grep hit is a lead, not a finding.

Process

Step 0: Load Engagement Context

Check for .harness/engagement.md. If present, load scope constraints — only scan in-scope paths and respect exclusions.

Check for THREAT_MODEL.md from a previous /threat-model run. If present, use its threat scenarios as scan targets. If absent, run full-surface scan.

Step 1: Map Entry Points to Trust Boundaries

Enumerate every place untrusted data enters the system, by reading the code:

  • External → app: HTTP handlers/routers, GraphQL resolvers, webhooks, file uploads, form fields, query params, headers
  • Process boundary: CLI args, environment variables, IPC, deserialization of stored data (cache, DB rows written earlier, config files)
  • Client-supplied state: cookies, JWT claims, API keys, referer/origin

For each entry point, note: what validation exists (yes/no/partial), and where the data flows next. This list is the scan's backbone — a scan that cannot name its entry points has not started.

Step 2: Trace Data Flow to Sinks

From each entry point, follow the data by reading code until it reaches a dangerous operation, or dies (validated, parameterized, dropped). Dangerous sink classes:

| Sink class | Examples (non-exhaustive) |

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

| Command/code execution | shell invocation, eval-family, template engines with code modes, deserialization to live objects |

| Query construction | string-built SQL, raw-query escapes in any ORM (Knex raw, Prisma $queryRaw, SQLAlchemy text(), Sequelize literal, Django extra/raw, Rails where("...") with interpolation) |

| Filesystem | path joins with user input, upload destinations, archive extraction (zip-slip), file reads driven by request params |

| Web output | template rendering with non-auto-escaping engines, innerHTML-family, redirect targets, header values (CRLF) |

| Auth decisions | IDOR — object lookups keyed only on user-supplied ids without ownership checks; role checks done client-side or per-endpoint instead of per-object |

Read the surrounding code for every candidate sink. A sink that only receives validated/parameterized data is not a finding; a sink reachable from an entry point with no validation is.

Step 3: Reason About Encoding and Context at Each Sink

For each reachable sink, ask what context the data lands in and whether the encoding matches:

  • Interpolated into a SQL string? → parameterize, don't escape
  • Interpolated into a shell string? → arg-array execution, don't quote
  • Rendered into HTML/JS/CSS/URL? → each needs context-specific output encoding; auto-escaping templates cover HTML only when actually enabled for that template
  • Joined into a path? → canonicalize, then verify containment inside the intended root
  • Deserialized? → prefer format + type that cannot instantiate attacker-chosen types

Step 4: Auth & Data-Exposure Pass

  • Default-deny: routes/actions missing an auth middleware or check entirely — enumerate handlers and look for the gaps, not the checks
  • Object-level authorization: for each handler that reads/writes a user-owned object, is ownership verified on THIS request?
  • Secrets: hardcoded credentials vs. config/env references; secrets in logs, error messages, client bundles, API responses
  • Error leakage: verbose errors/stack traces/config in production paths; error messages that distinguish "no such user" from "wrong password"

Step 5: Dependency Pass

cargo audit 2>/dev/null || echo "cargo-audit not installed"   # Rust
npm audit 2>/dev/null || echo "npm audit not available"       # Node.js

For each advisory: is a fix available, and is the vulnerable code path actually reachable from this codebase's usage? Unreachable advisories are LOW/INFO, not silent drops. Also flag actively-used dependencies that are unmaintained (no release in ~2+ years, archived repo) even without a CVE.

Grep as Accelerator, Not Oracle

Grep is fine for candidate sink locations (raw(, exec, innerHTML, eval, secret-ish identifiers) — use it to shortlist where to read. It misses framework-specific sinks, aliases, and data built across files. Never report a finding from a grep hit alone; never conclude "clean" because grep found nothing.

Step 6: Produce Output

Write VULN-FINDINGS.json:

{
  "scan_date": "ISO-8601",
  "scope": "full | incremental",
  "threat_model_ref": "THREAT_MODEL.md | null",
  "entry_points_traced": ["list every entry point examined — required for clean scans"],
  "findings": [
    {
      "id": "V1",
      "dimension": "injection | auth | exposure | dependency",
      "severity": "CRITICAL | HIGH | MEDIUM | LOW | INFO",
      "file": "path/to/file",
      "line": 42,
      "source": "untrusted-input origin (entry point)",
      "sink_chain": ["entry function", "...", "sink function"],
      "description": "what was found",
      "validated": true,
      "false_positive": false,
      "reachable": true,
      "mitigated": false,
      "threat_scenario": "T1 | null",
      "remediation": "one-line fix hint"
    }
  ],
  "summary": {
    "total": 10,
    "critical": 1,
    "high": 3,
    "medium": 4,
    "low": 2,
    "false_positives": 0
  }
}

Step 7: Feed into Triage

After producing findings, suggest:

"Run /triage to validate findings with adversarial review."

Anti-Rationalization

| Excuse | Rebuttal | What to do instead |

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

| "It's an internal tool / not user-facing" | Internal boundaries are attack surfaces — lateral movement starts inside. | Trace internal entry points with the same rigor. |

| "The framework sanitizes automatically" | Auto-escaping and parameterization have opt-outs, raw escapes, and edges; business logic is framework-agnostic. | Find the raw/dangerous escapes and read them. |

| "We'll add validation later" | Later never arrives for paths that already work. | Finding = now; remediation line goes in the output. |

| "Grep found nothing, so we're clean" | Grep misses aliased and framework-specific sinks by construction. | A clean claim requires traced entry points, not an empty grep. |

| "Dependencies are vetted" | Transitive dependencies aren't. | Run the dependency pass every time the lockfile changes. |

Evidence Required

  • [ ] Every finding cites file:line + the untrusted-input origin + the sink call chain
  • [ ] Each finding validated: reachable, not mitigated, severity confirmed
  • [ ] A clean (or low-finding) scan lists entry_points_traced — absence of evidence is not evidence of absence
  • [ ] All 4 dimensions completed (injection, auth, exposure, dependency)
  • [ ] VULN-FINDINGS.json written with summary
  • [ ] If THREAT_MODEL.md exists: each threat scenario mapped to findings
  • [ ] No CRITICAL/HIGH finding dismissed without explicit justification

Red Flags

  • Reporting grep hits without reading the surrounding code
  • Skipping framework-specific sink types (ORM raw escapes, non-auto-escaping templates)
  • Claiming clean without naming which entry points were traced
  • Scanning only changed files when full-surface scan was requested
  • Marking findings as false positives without a traced reason
  • VULN-FINDINGS.json with zero findings on a non-trivial codebase — the scan was likely incomplete, not the codebase clean

想直接用这个技能?

本站把开放许可(MIT / Apache 等)的技能按仓库打包整理到网盘,点一下转存到你自己的网盘,不用一个个从 GitHub 拉。许可未声明的技能只给原始仓库链接,不打包。