vuln-assessment-methodology · git:20260606.d4b92a2 · 2026-06-06 · sha256 1854f80d7614501b

vuln-assessment-methodology git:20260606.d4b92a2A

Immutable. This exact content is served forever at /api/v1/blob/1854f80d7614501b.

---
name: vuln-assessment-methodology
description: "Load when performing vulnerability assessment in any domain. Enforces source-to-sink tracing, disprove-first analysis, threat-model-aware severity, and finding quality standards. Prevents false positives and severity inflation."
---

# Vulnerability Assessment Methodology

**The goal is accurate, honest findings — not volume.** One correctly-assessed
finding is worth more than ten inflated ones.

## Hard Rules

### 1. NEVER report a sink without tracing the full data flow

Seeing a dangerous function is NOT a finding. Trace from **attacker-controlled
source** through every transformation to the sink. If sanitization exists, the
finding is invalid unless you demonstrate a specific bypass.

**Before reporting, answer:**
- What is the attacker-controlled input?
- What transformations does it undergo?
- Does any transformation neutralize the attack?
- Can you construct a concrete input that reaches the sink?

### 2. Try to DISPROVE your finding before reporting it

Actively look for evidence it is NOT exploitable. Read the FULL function. Look
for validation, input filtering, authorization checks, type constraints,
config gates. If you find defensive code, demonstrate a bypass or retract.

### 3. Severity must reflect the ACTUAL threat model

Assign severity by source, access, and context — not vulnerability class name.

| Source of dangerous input | Access required | Severity |
|---|---|---|
| HTTP request param | Unauthenticated, internet-facing | Critical/High |
| HTTP request param | Authenticated user | High/Medium |
| HTTP request param | Internal network only | Medium |
| Config/env var | Container-level access | Low |
| Hardcoded value (as sink input) | N/A | Not a finding (but hardcoded credentials are — actual secrets, not placeholders or example values) |

**What each level requires:**
- **Critical**: Unauth RCE, hardcoded prod credentials, full auth bypass. Attacker needs nothing beyond a network connection.
- **High**: Authed RCE, SQL injection via HTTP params, stored XSS, SSRF from internet-facing endpoint.
- **Medium**: Incomplete validation bypass, internal-only exposure, defense-in-depth gaps.
- **Low**: Defense-in-depth issues (env var in SQL), code quality that could become exploitable.
- **Not a finding**: Complete upstream sanitization, config-as-designed, token parsed for metadata only, framework defaults, attacker already needs higher privileges.

### 4. Read the COMPLETE defensive code

If validation exists but is incomplete (e.g., blocks `;` but not `"`), report
the **specific bypass**, not "no sanitization." Severity reflects the bypass
narrowness, not unrestricted injection impact.

- BAD: "Command injection via bash -c with no sanitization" (HIGH)
- GOOD: "Incomplete validation in ValidateCommand() — misses `\"`, allowing
  quote-escape from bash -c wrapping" (MEDIUM)

### 5. Configuration options are not vulnerabilities

Dev mode / unsecured mode is a design decision unless attacker-toggleable.

### 6. Internal tools have different threat models

Report missing auth on internal tools as a **dependency on network controls**,
not "missing security." Don't assign CRITICAL unless evidence shows internet
exposure.

### 7. AI prompt injection is a design concern, not a code bug

Not a code vulnerability unless AI output feeds a security-sensitive sink
(e.g., `eval()`, SQL, shell commands, file paths, unencoded HTML).

### 8. Distinguish application code from framework code

Don't report framework defaults as vulnerabilities.

### 9. Flag obvious attack chains — do not force them

When multiple findings converge on a single exploitable outcome, note the
chain. An IDOR + information disclosure + missing rate limiting may each be
Medium alone but chain to account takeover. Report the chain as an additional
compound finding with its own severity reflecting the combined impact — keep
the individual findings too, since each needs its own remediation. Do not
exhaustively search for chains — flag them when apparent from findings already
identified.

## Confidence Levels

Every finding must include a confidence level. When the full source-to-sink
trace is complete, mark it Confirmed. When it is not, classify the gap.

| Level | Criteria | Documentation required |
|---|---|---|
| Confirmed | Full trace complete, concrete payload constructable | Complete data flow from source to sink with specific input |
| Probable | Most of trace complete, specific gap identified | State the exact gap (e.g., "dynamic dispatch at line 42 — two implementors exist, both pass input unsanitized") |
| Suspected | Pattern match or shallow trace only | State what additional analysis (dynamic testing, debug tracing, etc.) would confirm or refute |

Common trace gaps: dynamic dispatch, reflection, external dependencies, plugin
systems, runtime-generated code. Always name the specific mechanism that
blocked the trace.

## Reporting Standards

Reports must:
- State access prerequisites explicitly
- Note existing defensive code and why it's insufficient
- Map each finding to the most specific applicable CWE ID (leaf-level variant,
  not the pillar — e.g., CWE-89 not CWE-74)
- Include specific, actionable remediation referencing the technology in use
  and the code location where the fix applies (not "add input validation" but
  "use parameterized queries via `db.Query()` with placeholder args at
  `handler.go:47`")
- When multiple findings share a root cause, report one root-cause finding
  with a list of affected locations rather than separate findings per instance
- State what was analyzed and what was not — files, components, and entry
  points covered, plus what could not be assessed (runtime behavior,
  infrastructure config, third-party dependency internals)
- Be defensible under peer review by a senior security engineer

## Proof-of-Concept Validation (Opt-in)

Default behavior is to trace data flow and assess exploitability conceptually.
Do not construct payloads or simulate execution unless the user requests it.

If the user requests proof-of-concept validation:
- Construct a concrete payload that demonstrates the vulnerability
- Document exact attacker-controlled input values
- Show the code path execution trace from source to sink
- State environmental prerequisites (auth state, config, timing)
- For web targets: provide the specific HTTP request that triggers the issue

## Anti-patterns

| Anti-pattern | Example | Why it's wrong |
|---|---|---|
| Sink-only analysis | "Dangerous function found → vuln" | Didn't check upstream defenses |
| Ignoring defensive code | "Injection, no sanitization" when validation exists | Didn't read the full function |
| Class-name severity | "SQL injection → HIGH" regardless of source | Env var source ≠ HTTP param source |
| Feature-as-vulnerability | "Unsecured mode exists" | Documented design decision |
| Framework noise | "Framework uses cookies" | Expected framework behavior |
| Theoretical-only | "If attacker could modify env vars..." | Attacker already has code exec |
| Quantity over quality | 10 low-confidence findings | 1 verified > 10 guesses |
| Context-free severity | "No auth → CRITICAL" on internal tool | Deployment model matters |
| Confirmation bias | Rationalizing why mitigations don't count | Try to disprove first |
| Forced chaining | "These 3 lows chain to Critical" without shared attack flow | Chain must converge on a single exploitable outcome, not just co-exist |
| Generic remediation | "Add input validation" | Must name specific fix and code location |
| Duplicate inflation | 15 separate XSS findings from one missing encoder | One root cause = one finding + affected locations |