Vulnerability Patterns & Web Mitigation Strategies

Web application vulnerabilities do not arrive in isolation — they cluster into recurring attack patterns that exploit predictable gaps in input handling, session management, network boundaries, and output rendering. This guide maps those patterns to concrete mitigations, audit controls, and CI/CD enforcement gates for full-stack engineers and security teams operating under OWASP Top 10, NIST SP 800-53, OWASP ASVS, and SOC 2 compliance requirements.

The six primary topic areas below form a defence-in-depth stack: Cross-Site Scripting (XSS) Mitigation addresses output-encoding failures in browser contexts; injection attack prevention covers server-side query and command interfaces; and Cross-Site Request Forgery (CSRF) defence closes the gap between authenticated sessions and cross-origin state mutation. Every section here links to the deeper reference pages where runnable code, bypass patterns, and compliance evidence templates live.


Web Vulnerability Mitigation Stack Architecture diagram showing an untrusted client passing through a WAF/CDN gateway layer, an authentication and session boundary, an application logic layer, and a data persistence layer. Each boundary is annotated with the primary vulnerability controls applied at that layer. Browser (untrusted) XSS · CSRF · Open Redirect WAF / CDN (boundary) TLS termination Security headers Rate limiting WAF ruleset CSP injection Auth Layer (boundary) JWT validation CSRF token check SameSite cookies Session rotation Origin validation App Logic (trusted) Parameterised queries Output encoding SSRF host allowlist RBAC enforcement DOM sanitisation Data Layer Least-privilege IAM Encryption at rest Untrusted Boundary Trusted Web Application Defence Stack — Trust Zone Overview Controls applied at each trust boundary reduce the attack surface before requests reach the data layer

Core Principles & Compliance Alignment

Web mitigations are only auditable when they map to explicit control requirements. The table below cross-references each principle with the mandatory artifact auditors expect and the engineering step that produces it.

Framework Control ID Required Artifact Engineering Validation Step
OWASP ASVS 4.0 V5.1 — Input Validation Parameterised query logs, sanitisation unit tests Code review gate + SAST scan blocking on SQL sink patterns
NIST SP 800-53 SI-10 — Input Validation Validated input schema definitions, test results Automated JSON schema validation in CI
SOC 2 CC6.1 — Logical Access RBAC matrix, JWT audience/issuer validation logs Token validation unit tests + access-log review
SOC 2 CC6.6 — Boundary Protection CSP headers, WAF rule export, egress allowlist DAST header scan + network policy review
SOC 2 CC7.2 — System Monitoring SIEM alert definitions, RASP telemetry exports Runtime log review + alerting runbook
OWASP ASVS 4.0 V3.4 — Cookie Security Cookie attribute audit (Secure, HttpOnly, SameSite) Response header DAST check
NIST SP 800-53 SC-12 — Cryptographic Key Mgmt Key rotation policy, KMS audit trail Quarterly key rotation evidence + KMS log export
ISO 27001 A.14.2.1 — Secure Development Secure coding standard, peer-review logs PR checklist + SAST report archival
OWASP ASVS 4.0 V13.2 — RESTful API Security API input schema, anti-CSRF proof for state-mutating endpoints API DAST scan + schema validation CI step

The overarching principle is defence in depth: no single control is sufficient. A WAF catches known signatures; source-level encoding prevents classes of unknown payloads; security headers constrain the browser execution environment; and runtime monitoring detects exploitation attempts that bypass all of the above. Each layer is independently auditable.

System Decomposition & Architecture

Before selecting mitigations, decompose the system into trust zones. Every zone transition — browser to CDN, CDN to auth service, auth service to application, application to database — is a boundary where controls must be placed. Leaving a zone transition unguarded is equivalent to leaving a door open between a public corridor and a server room.

The diagram above shows the canonical three-zone web application model:

  • Untrusted zone (browser / API client): origin of all attacker-controlled input. Controls here focus on restricting what the browser is permitted to execute (CSP, Trusted Types, SameSite cookies).
  • Boundary zone (WAF, CDN, API gateway, auth service): where TLS terminates, identity is verified, rate limiting runs, and security response headers are injected. This is the primary enforcement point for secure HTTP header configuration.
  • Trusted zone (application logic, data layer): where business logic runs. Controls here focus on ensuring that even if boundary controls are bypassed, untrusted data cannot drive dangerous operations — parameterised queries, output encoding, SSRF host allowlists, RBAC checks.

For multi-tenant SaaS systems, add a fourth zone: tenant isolation boundaries within the trusted zone, enforced via row-level security and tenant-scoped IAM roles. Refer to the attack surface mapping techniques for tooling to discover unmarked zone transitions automatically.

Threat Identification & Classification

The following taxonomy maps each primary web vulnerability class to its STRIDE category, affected component, MITRE ATT&CK technique, and the secure control that closes the gap.

Vulnerability Class STRIDE Category Target Component MITRE ATT&CK Technique Secure Control Baseline
Reflected / Stored XSS Tampering, Elevation of Privilege DOM, HTML output layer T1059.007 — JavaScript Execution Context-aware output encoding; CSP script-src; Trusted Types
SQL / NoSQL Injection Tampering, Information Disclosure Database query interface T1190 — Exploit Public-Facing App Parameterised queries; ORM query binding; input allowlisting
CSRF Spoofing State-mutating HTTP endpoints T1556 — Modify Authentication Process Double-submit cookie; SameSite=Strict; Origin header validation
SSRF Information Disclosure, Lateral Movement Server-side HTTP client T1590 — Gather Victim Network Info Host/scheme allowlist; DNS resolution validation; metadata IP blocking
DOM-Based XSS Tampering Browser DOM sinks T1059.007 — JavaScript Execution DOMPurify sanitisation; avoid innerHTML/eval; CSP unsafe-eval ban
Open Redirect Spoofing Redirect endpoints T1598 — Phishing for Info Hard-coded redirect allowlist; relative-path-only redirects
Clickjacking Tampering Frame rendering T1185 — Browser Session Hijack X-Frame-Options: DENY; frame-ancestors 'none' CSP directive
Header Injection Tampering HTTP response construction T1190 — Exploit Public-Facing App Strip newline characters from header values at the framework layer
Insecure Deserialisation Elevation of Privilege Object deserialisation T1059 — Command and Scripting Type-safe deserialisation; allowlist permitted classes; HMAC payload signing

Cross-reference this taxonomy with the STRIDE framework implementation guide, which provides step-by-step data-flow analysis procedures for applying these categories to each service in a microservices architecture.

Risk Assessment & Mitigation Mapping

Prioritise remediation using a combined CVSS 4.0 and EPSS model. CVSS base scores measure theoretical severity; EPSS scores measure empirically observed exploitation probability within 30 days. Remediating only on CVSS generates noise; combining them focuses engineering time where attacker activity is highest.

Scoring Axis Metric Threshold Remediation SLA
CVSS 4.0 Base Attack Vector + Impact >= 9.0 (Critical) 24 hours
CVSS 4.0 Base Attack Vector + Impact 7.0–8.9 (High) 14 days
CVSS 4.0 Base Attack Vector + Impact 4.0–6.9 (Medium) Sprint cycle
EPSS 30-day exploitation probability >= 0.5 (50%) Upgrade to next tier SLA
DREAD (legacy) Damage × Reproducibility × Exploitability × Affected Users × Discoverability Score >= 15 Treat as High

The following TypeScript implementation demonstrates the primary mitigation layer for DOM output: a context-aware sanitisation wrapper that enforces DOMPurify allowlists before any untrusted content touches the DOM.

import DOMPurify from 'dompurify';

/** Controls which HTML tags and attributes survive sanitisation in different contexts. */
const RICH_TEXT_CONFIG: DOMPurify.Config = {
  ALLOWED_TAGS: ['p', 'strong', 'em', 'ul', 'ol', 'li', 'a', 'br', 'code'],
  ALLOWED_ATTR: ['href', 'title', 'rel'],
  FORBID_ATTR: ['onerror', 'onload', 'onclick', 'style'],
  ADD_ATTR: ['target'],
  RETURN_DOM_FRAGMENT: false,
};

/** Plain-text context: strip all tags entirely. */
const PLAIN_TEXT_CONFIG: DOMPurify.Config = {
  ALLOWED_TAGS: [],
  ALLOWED_ATTR: [],
};

/**
 * Sanitise HTML for insertion into a rich-text container (e.g. blog body).
 * Never call this for URL, attribute, or JavaScript contexts — use the
 * dedicated functions below for those cases.
 */
export function sanitiseRichText(raw: string): string {
  if (!raw) return '';
  return DOMPurify.sanitize(raw, RICH_TEXT_CONFIG) as string;
}

/** Sanitise content that will be inserted as text-only — no HTML permitted. */
export function sanitisePlainText(raw: string): string {
  if (!raw) return '';
  return DOMPurify.sanitize(raw, PLAIN_TEXT_CONFIG) as string;
}

/**
 * Validate a redirect target.
 * Allows only relative paths to prevent open-redirect phishing chains.
 */
export function safeRedirectPath(target: string, fallback = '/'): string {
  if (!target) return fallback;
  // Reject absolute URLs and protocol-relative URLs
  if (/^(https?:)?\/\//i.test(target)) return fallback;
  // Reject javascript: and data: schemes
  if (/^(javascript|data|vbscript):/i.test(target.trim())) return fallback;
  return target;
}

For server-side injection attack prevention, parameterised queries are the canonical baseline. The same principle applies to NoSQL operators: never concatenate user-supplied strings into a MongoDB $where clause or an Elasticsearch query DSL fragment.

For server-side request forgery (SSRF) prevention, the critical control is resolving the target hostname before allowing the outbound request and validating the resolved IP against a blocklist of RFC-1918 and cloud metadata ranges.

Validation, Auditing & Continuous Integration

Security controls that are not enforced in the build pipeline are not controls — they are suggestions. The following GitHub Actions configuration gates merges on SAST findings, DAST header scans, and compliance report generation.

name: Security Validation Gate
on:
  pull_request:
    branches: [main, develop]

jobs:
  sast:
    name: Static Analysis (SAST)
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Semgrep OWASP Top 10
        uses: semgrep/semgrep-action@v1
        with:
          config: >-
            p/owasp-top-ten
            p/default
          generateSarif: "1"
        env:
          SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }}
      - name: Upload SARIF
        uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: semgrep.sarif

  dast-headers:
    name: Security Header Validation (DAST)
    runs-on: ubuntu-latest
    needs: sast
    steps:
      - uses: actions/checkout@v4
      - name: ZAP Header Scan
        uses: zaproxy/action-full-[email protected]
        with:
          target: ${{ vars.STAGING_URL }}
          rules_file_name: '.zap/rules.tsv'
          cmd_options: '-a'
      - name: Extract High/Medium Findings
        run: |
          jq -r '.alerts[]
            | select(.risk == "High" or .risk == "Medium")
            | "| \(.alert) | \(.risk) | \(.solution) |"' zap_results.json \
            > findings.md
          CRITICAL_COUNT=$(jq '[.alerts[] | select(.risk == "High")] | length' zap_results.json)
          if [ "$CRITICAL_COUNT" -gt 0 ]; then
            echo "::error::$CRITICAL_COUNT High-severity findings — merge blocked"
            exit 1
          fi
      - name: Upload Audit Evidence
        uses: actions/upload-artifact@v4
        with:
          name: security-audit-evidence-${{ github.run_id }}
          retention-days: 90
          path: |
            semgrep.sarif
            zap_results.json
            findings.md

  policy-as-code:
    name: Header Policy Enforcement
    runs-on: ubuntu-latest
    needs: dast-headers
    steps:
      - uses: actions/checkout@v4
      - name: Validate CSP via schema
        run: |
          npx csp-validator --config .security/csp-policy.json \
            --report-uri "${{ vars.STAGING_URL }}"

The JSON policy file below defines the header requirements that the csp-validator step enforces. Store this as .security/csp-policy.json in the repository root.

{
  "required_headers": {
    "Content-Security-Policy": {
      "directives": {
        "default-src": ["'self'"],
        "script-src": ["'self'"],
        "object-src": ["'none'"],
        "base-uri": ["'self'"],
        "frame-ancestors": ["'none'"]
      }
    },
    "X-Frame-Options": "DENY",
    "X-Content-Type-Options": "nosniff",
    "Referrer-Policy": "strict-origin-when-cross-origin",
    "Permissions-Policy": "geolocation=(), camera=(), microphone=()"
  },
  "forbidden_headers": ["Server", "X-Powered-By"],
  "strict_transport": {
    "max_age": 63072000,
    "include_subdomains": true,
    "preload": true
  }
}

See secure HTTP header configuration for the full directive reference and edge-case handling for multi-origin CDN deployments.

Documentation & Knowledge Transfer

Audit readiness requires living documentation, not one-time reports. The following markdown template captures the per-vulnerability threat model record that satisfies SOC 2 Type II evidence requirements and supports the sprint-level knowledge transfer that prevents recurring vulnerabilities.

## Vulnerability Record — [VULN-ID]: [Short Title]

**Reported:** YYYY-MM-DD  
**Reporter:** [Engineer / Scanner]  
**Severity:** [Critical / High / Medium / Low]  
**CVSS 4.0:** [score]  
**EPSS:** [probability]  
**OWASP Category:** [A0X:YYYY — Category Name]  
**NIST Control:** [SI-10 / SC-12 / AC-6 / etc.]  
**SOC 2 Criteria:** [CC6.1 / CC6.6 / CC7.2]

### Affected Component
[Service name, file path, endpoint, or data-flow segment]

### Attack Scenario
[1–3 sentences describing a realistic exploitation path]

### Root Cause
[Missing control, incorrect configuration, or unsafe API usage]

### Remediation Applied
- [ ] Source-level fix: [PR link]
- [ ] SAST rule updated: [rule ID]
- [ ] DAST baseline updated: [scan config change]
- [ ] Security header added/modified: [header name]

### Verification Evidence
- [ ] Unit test added: [test file path]
- [ ] CI gate passing: [workflow run link]
- [ ] Compliance artifact generated: [artifact name]

### Recurrence Prevention
[Pattern or coding standard change to prevent this class of vulnerability]

For team-scale knowledge transfer, file a Jira/Linear security ticket with this template attached as a linked document and tag it with your security label (security, compliance). Link the ticket to the sprint story that introduced the vulnerability if traceable. Teams using DREAD or risk-register workflows should attach the scoring worksheet to the same ticket.

Common Mistakes Checklist

These are the architectural and implementation anti-patterns that generate the most recurring vulnerabilities in production web applications. Review them before each security sprint or penetration-test scope definition.

Frequently Asked Questions

How do web vulnerability patterns map to OWASP Top 10 and NIST controls?

Each OWASP category (A03 Injection, A07 XSS, A08 CSRF) maps to one or more NIST SP 800-53 controls. A03 maps to SI-10 (Input Validation) and CM-8; A07 maps to SI-10 and SC-18 (Mobile Code); A08 maps to AC-3 and AC-6. Implementing context-aware encoding and parameterised queries simultaneously satisfies the OWASP ASVS V5 requirements and provides the audit evidence NIST auditors expect. The compliance table in the section above lists specific control IDs and required artifacts for each mapping.

What is the difference between SAST and DAST for vulnerability validation?

SAST analyses source code before deployment, catching injection sinks, unsafe deserialisation, and missing security headers at the PR stage — zero runtime required. DAST probes a running application, discovering reflected XSS, SSRF, and open redirect vulnerabilities that only manifest at runtime. Both are required for SOC 2 CC6.6 evidence. Treat them as complementary: SAST has high false-positive rates for business logic; DAST has coverage gaps for authenticated flows.

How often should vulnerability mitigations be reviewed?

Review quarterly or immediately following major framework releases, CVEs affecting your dependency tree, or OWASP ASVS baseline updates. Tie the review cadence to your risk register SLA: CVSS >= 9.0 within 24 hours, >= 7.0 within 14 days, lower within a sprint cycle. Combine CVSS scores with EPSS probability — a CVSS 6.5 finding with EPSS 0.72 deserves the same urgency as a CVSS 8.0.

Can a WAF replace source-level input validation?

No. WAF rules are a defence-in-depth layer, not a substitute. Encoding bypasses (double-URL encoding, Unicode normalisation, HTML entity confusion), zero-day payloads, and application-specific business-logic flaws routinely evade WAF signatures. NIST SI-10 explicitly requires input validation at the application layer regardless of perimeter controls. A WAF that blocks a novel attack buys hours; source-level parameterised queries prevent the entire attack class permanently.

Which SOC 2 trust criteria do web vulnerability mitigations satisfy?

CC6.1 (logical access restricted to authorised entities), CC6.6 (boundary protection and network segmentation), and CC7.2 (system monitoring and anomaly detection) are the primary criteria. Injection prevention and CSRF defence contribute evidence to CC6.1 and CC6.6. Runtime monitoring via RASP and SIEM feeds CC7.2. Audit artefacts include scan SARIF files, CI gate pass/fail logs, and cookie-attribute DAST reports — all retained for 12 months under SOC 2 Type II requirements.

What is EPSS and why use it alongside CVSS?

EPSS (Exploit Prediction Scoring System) estimates the probability that a given CVE will be exploited in the wild within 30 days, derived from observed exploitation telemetry across the internet. CVSS measures theoretical severity, not exploitation likelihood — a CVSS 9.8 finding with EPSS 0.003 may sit unpatched for a sprint cycle without material risk, while a CVSS 6.5 finding with EPSS 0.85 is actively being weaponised. Combining both scores reduces false-priority noise and focuses remediation where real attacker activity is highest.