Principles & Severity

Principles & Severity

The philosophy that separates a useful audit from a checklist dump — plus how severity is actually decided.

Only report what you can exploit

Every finding needs a concrete attack scenario. "Send this request, get this result" — never "an attacker could theoretically…".

Adversarial validation

The agent that checks a finding is never the agent that found it. Hunters find; a separate validator tries to disprove.

Severity requires impact

Severity = likelihood × impact, on both axes. If you can't describe the concrete damage, the severity is lower than you think.

Defense-in-depth gaps aren't bugs

If Layer A already prevents the attack, the absence of Layer B is a hardening suggestion — report it separately, don't inflate it.

Determine the baseline dynamically

Identify comparable software and calibrate. Same pattern exploited elsewhere? Stronger finding. Never exploited in 20 years? Understand why first.

Multiple runs improve coverage

A single run finds roughly half. Re-running with prior findings in hand keeps surfacing new ground.

Severity rubric

The HIGH-vs-MEDIUM line for business logic: does the finding defeat an explicit security boundary?

CRITICAL

Unauthenticated RCE, full database dump, admin account takeover without credentials.

HIGH

Authenticated RCE, SQLi with exfiltration, stored XSS firing for all users, auth bypass, or an RBAC model completely defeated for a consequential action.

MEDIUM

Targeted XSS needing specific conditions, CSRF with meaningful state change, secrets disclosure, or business-logic bypass with real but limited consequences.

LOW

Non-secret information disclosure, DoS requiring sustained effort, hardening gaps.

Anti-patterns to avoid

The mistakes that make security audits useless.

  1. OWASP as a bug list

    Listing everything that deviates from OWASP. It's a checklist, not a bug list; every real app makes tradeoffs.

  2. Inflated defense-in-depth

    Rating a missing redundant check as HIGH/CRITICAL when the query builder already quotes identifiers.

  3. Ignoring the deployment model

    Rate limiting at the CDN is valid architecture; not every app needs app-level rate limiting.

  4. Designed behavior as a bug

    If the trust model says admins are fully trusted, admins doing admin things is not a finding.

  5. Padding with LOWs

    Ten LOWs don't make a useful report. Three real MEDIUMs do.

  6. "Potential" findings

    Either you can exploit it or you can't. If you need "potentially", you haven't done enough research.

  7. Ignoring what's done well

    Saying auth is solid builds trust in the findings you do report and helps prioritization.

  8. Guessing parser/runtime behavior

    The most convincing false positives reason "the runtime will interpret this as…" without verifying. Cite the spec or test it.

  9. Skipping logic & creativity

    Scanners check SQLi/XSS/SSRF. A manual audit's value is logic errors, state-machine violations, and chained attacks.

  10. Giving up too easily

    "It uses parameterized queries" is lazy. Check every sql.raw(), dynamic identifiers, search/FTS, and bypass paths. Push.