---
name: detect-ssrf
description: "Detection and response methodology for Server-Side Request Forgery (SSRF), where a public-facing application is coerced into making attacker-controlled requests, most dangerously to the cloud metadata endpoint (169.254.169.254) to steal instance-role credentials (MITRE ATT&CK T1190, T1552.005, and T1046 for internal pivoting). Covers application and WAF access logs, VPC Flow Logs and egress proxy logs, CloudTrail assumed-role credential-use anomalies, and GuardDuty InstanceCredentialExfiltration findings; gives the method for spotting metadata-endpoint access, egress anomalies, and allowlist bypasses, plus IMDSv2 and least-privilege hardening. Use when detecting or hunting SSRF, triaging a URL-fetch or webhook parameter that reached an internal address, investigating stolen EC2 instance credentials, detecting access to the cloud metadata service, or hardening a service against metadata credential theft."
---

# Server-Side Request Forgery (SSRF) - Defensive Methodology

> **Tier 2 - methodology skill.** No bespoke UMBRASEC detection rule ships with this skill yet. It gives the defender's method, the log sources and signals, the hunt, and the hardening, and points to public rule sources. Promotion to Tier 1 (a sourced, tuned UMBRASEC rule) is tracked in [COVERAGE.md](https://github.com/umbrasec-labs/umbra-blue/blob/main/COVERAGE.md). Do not treat the content below as citing a UMBRASEC rule; there is none for this threat yet.

## TL;DR for defenders

SSRF turns a server that fetches URLs (webhooks, link previews, PDF or image renderers, file importers, open-redirect-following proxies) into a request generator the attacker steers. The crown-jewel target is the cloud instance metadata endpoint at `169.254.169.254` (plus `fd00:ec2::254`, `metadata.google.internal`, and Alibaba's `100.100.100.200`), because a single hit can return instance-role credentials the attacker then uses from elsewhere. Your three highest-value signals are: application or WAF logs showing a user-supplied URL pointing at internal or link-local address space, a cloud credential-use anomaly where an instance role is used from an IP that is not the instance (AWS GuardDuty catches this natively), and egress-proxy or flow-log evidence of the app tier reaching services it never normally contacts. The single most important thing to understand is that the metadata hit itself is usually invisible to VPC Flow Logs, so you detect the downstream credential misuse, not the request.

## What it looks like, defender view

In telemetry, SSRF presents as a legitimate-looking request to your application carrying a URL, hostname, or IP in a parameter, header, or body that resolves to somewhere the app has no business fetching: a private RFC1918 range, loopback, link-local `169.254.0.0/16`, or a cloud metadata hostname. The follow-on, when credentials are taken, shows up far away from the web tier: an assumed-role session whose name is the instance ID is suddenly exercised from an external or unexpected source IP. Allowlist-bypass attempts look like odd address encodings (decimal, octal, or hex IP literals, IPv6-mapped addresses, trailing-dot or enclosed-alphanumeric hostnames) or a benign hostname that resolves to an internal address (DNS rebinding) and redirect chains that start external and end internal.

## Log sources and signals

- **Application and WAF access logs** (nginx or Apache access logs, AWS/ALB access logs, Cloudflare/Akamai/AWS WAF logs). Inspect the request parameters, JSON body fields, and headers that feed a server-side fetcher. The signal is a user-controlled URL whose host is `169.254.169.254`, `metadata.google.internal`, `100.100.100.200`, `fd00:ec2::254`, `localhost`/`127.0.0.1`, or an RFC1918 address, including obfuscated encodings. Non-HTTP schemes such as `file://`, `gopher://`, and `dict://` in a URL parameter are a strong tell.
- **Server-side fetcher instrumentation.** The actionable control is logging the final resolved destination IP after DNS resolution and after all redirects, not the input string. Input-string matching is the weak form because decimal/octal/hex IP literals, IPv6-mapped addresses, open-redirect chaining, and DNS rebinding all defeat it. Log the post-resolution peer address so the allowlist decision and the detection both key off ground truth.
- **CloudTrail (AWS).** The stolen-credential signal is a record where `userIdentity.type=AssumedRole` and `sessionContext.sessionIssuer.type=Role`, the role-session name equals the instance ID (`i-...`), and `sourceIPAddress` is not the instance's egress IP (for example a non-AWS or cross-account address). Also watch `ModifyInstanceMetadataOptions` for `HttpTokens` changing from `required` to `optional` or the hop limit being raised, which weakens IMDS back to the exploitable state.
- **AWS GuardDuty findings.** `UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration.OutsideAWS` and `...InstanceCredentialExfiltration.InsideAWS` are high-fidelity: they fire when instance-role credentials are used from outside the instance. This is the most reliable native signal that an IMDS theft succeeded.
- **VPC Flow Logs and egress proxy logs.** Use `srcaddr`, `dstaddr`, `dstport`, and `action` to spot the app tier making outbound connections to internal hosts or ports it never normally contacts (SSRF used for internal recon and port scanning). Egress-proxy (Squid, Zscaler, or equivalent) logs capture the outbound fetch destinations directly, which flow logs that exclude link-local traffic do not.
- **DNS query logs** (Route 53 Resolver query logs, or Zeek `dns.log`). For the allowlist-bypass focus, alert when a hostname submitted to a fetcher resolves to an RFC1918 or link-local answer, which is the DNS-rebinding tell.
- **Container runtime (Falco / cloud-native).** For containerized apps, host-level egress telemetry showing a container reaching `169.254.169.254` is a direct signal.
- **Azure and GCP equivalents.** Azure IMDS at `169.254.169.254` requires the `Metadata: true` header; Microsoft Defender for Cloud and NSG flow logs carry the signal. GCP metadata at `metadata.google.internal` requires `Metadata-Flavor: Google`; requests to legacy `v1beta1` metadata paths (which did not require the header) are a notable anomaly, which flow logs and Cloud Audit Logs generally do not record, so detect it at the application or host layer (and note the legacy v1beta1 endpoint has been turned down).

## Detection approach

Alert in three layers, because no single source is complete. At the application edge, match the fetched URL (parameter, body, and header) against internal, loopback, and link-local address space and the known metadata hostnames across their encodings, and flag non-HTTP schemes. At the cloud control plane, alert on the assumed-role credential-use anomaly described above and surface GuardDuty InstanceCredentialExfiltration findings directly to the SOC queue, since those are near-binary. At the network layer, baseline the app tier's normal egress and alert on new internal destinations or port-scan-like fan-out.

A tuned UMBRASEC rule is not yet shipped for SSRF. For public, maintained rules, see the SigmaHQ web and proxy rule directories at [github.com/SigmaHQ/sigma/tree/master/rules/web](https://github.com/SigmaHQ/sigma/tree/master/rules/web) and [.../rules/web/proxy_generic](https://github.com/SigmaHQ/sigma/tree/master/rules/web/proxy_generic), the AWS CloudTrail directory at [.../rules/cloud/aws/cloudtrail](https://github.com/SigmaHQ/sigma/tree/master/rules/cloud/aws/cloudtrail), and the emerging-threats directory for CVE-specific SSRF chains at [.../rules-emerging-threats](https://github.com/SigmaHQ/sigma/tree/master/rules-emerging-threats). For containers, the Falco default rule set at [github.com/falcosecurity/rules](https://github.com/falcosecurity/rules) includes a rule that fires when a container contacts the cloud metadata service. For the cloud credential-misuse signal, lean on AWS GuardDuty's InstanceCredentialExfiltration finding types rather than rebuilding them.

## Threat hunt

Hypothesis: a public-facing fetcher was coerced into reaching the metadata endpoint and the instance role was exfiltrated.

1. In application and WAF access logs over the window, pull every request whose URL-bearing parameters, JSON body, or headers contain `169.254.169.254`, `fd00:ec2::254`, `metadata.google.internal`, `100.100.100.200`, `localhost`, `127.0.0.1`, RFC1918 ranges, or a non-HTTP scheme (`file:`, `gopher:`, `dict:`).
2. Re-run the search normalizing for bypass encodings: decimal, octal, and hex IP literals, IPv6-mapped forms, trailing-dot and enclosed-alphanumeric hostnames. Where you log the post-resolution destination IP, hunt on that field instead, which collapses all encodings.
3. In DNS query logs, find any hostname passed to a fetcher that resolved to an RFC1918 or link-local answer (DNS rebinding).
4. For each candidate instance, pivot to CloudTrail: did an assumed-role session whose name is that instance ID get used from a `sourceIPAddress` that is not the instance shortly after the suspect request? Pull every API call made by that session to scope the blast radius.
5. Review GuardDuty `InstanceCredentialExfiltration.OutsideAWS` and `.InsideAWS` findings across the same window and correlate to the instances above.
6. For internal-recon use of SSRF, review VPC Flow Logs or egress-proxy logs for the app tier reaching internal hosts or ports outside its baseline, especially sequential-port fan-out.

## Hardening

The durable fixes make a successful SSRF low-value and the metadata path unreachable. Enforce IMDSv2 so every metadata request needs a signed session token (AWS `HttpTokens=required`); the hop limit of 1 is the default and blocks a bridged container from reaching IMDS, but audit it rather than assume, because EKS worker nodes commonly run a hop limit of 2. The AWS Config managed rule `ec2-imdsv2-check` reports instances that still allow IMDSv1. On EKS, use IRSA or EKS Pod Identity so pods get their own scoped credentials and do not fall back to the node instance role. Apply egress filtering so the app tier can only reach an outbound allowlist, and block `169.254.0.0/16` and other link-local and internal ranges at the host firewall or egress proxy. Use IAM condition keys such as `aws:EC2InstanceSourceVPC` and `aws:EC2InstanceSourcePrivateIPv4` to deny instance-role credentials used from outside the instance's VPC, which directly neuters a stolen metadata credential. Azure and GCP require their metadata headers (`Metadata: true`, `Metadata-Flavor: Google`); treat requests without them, and GCP legacy `v1beta1` access, as hostile.

The controls below map to the codes used in the UMBRASEC [identity and access guide](https://umbrasec.dev/guide/identity-and-access.html) and [detection and response guide](https://umbrasec.dev/guide/detection-and-response.html); IMDSv2 enforcement and egress filtering are left to the prose above because no single framework control maps cleanly to them.

| Control | What it does | Essential Eight | ISO 27001:2022 | NIST CSF 2.0 |
|---|---|---|---|---|
| Least-privilege instance and pod roles | Shrinks the value of stolen metadata credentials so exfiltration buys little | Restrict administrative privileges (ML2+) | A.8.2 Privileged access rights | PR.AA-05 Least privilege |
| Patch and update the server-side fetcher | Removes SSRF-prone URL-fetch, PDF, SVG, and image-proxy components at the source | Patch applications | A.8.8 Technical vulnerabilities | PR.PS Platform security |
| Log and monitor app-tier egress and role use | Supplies the telemetry every detection above depends on | ML2/ML3 event-log collection | A.8.15 Logging; A.8.16 Monitoring | DE.CM Continuous monitoring; DE.AE Adverse events |

## Honest limitations

- **The metadata hit is usually invisible to VPC Flow Logs.** Traffic to the link-local `169.254.169.254` endpoint is not captured by VPC Flow Logs, so you generally cannot see the SSRF request to IMDS there; you detect the downstream credential misuse (CloudTrail and GuardDuty) and the application-layer request instead. Lead your detection with those, not with flow logs.
- **Blind SSRF leaves little at the app layer.** When the response is not reflected to the attacker, the application log may show only an ordinary request; the credential-use anomaly and egress telemetry become your primary evidence.
- **Input-string matching is defeated by bypasses.** Decimal, octal, and hex IP literals, IPv6-mapped addresses, open-redirect chaining, and DNS rebinding all evade naive parameter matching. Only logging and keying off the post-resolution destination IP closes this gap.
- **Benign server-side fetchers are a real false-positive source.** Webhooks, link-preview and unfurl services, PDF and image renderers, and import features legitimately fetch external URLs; some even legitimately reach internal services. Baseline them and allowlist before enforcing, or the detections will be noisy.
- **IMDSv1-era access produces no network log you control.** If IMDSv2 is not enforced, the credential theft can be a single clean request with no distinct, ownable network record, which is exactly why the IMDSv2 and IAM-condition-key hardening matters as much as the detection.

## ATT&CK and D3FEND

- MITRE ATT&CK: [T1190 Exploit Public-Facing Application](https://attack.mitre.org/techniques/T1190/) (Initial Access) for the SSRF itself, [T1552.005 Unsecured Credentials: Cloud Instance Metadata API](https://attack.mitre.org/techniques/T1552/005/) (Credential Access) for the metadata credential theft, and [T1046 Network Service Discovery](https://attack.mitre.org/techniques/T1046/) (Discovery) for SSRF used to scan internal services.
- MITRE D3FEND: [D3-OTF Outbound Traffic Filtering](https://d3fend.mitre.org/technique/d3f:OutboundTrafficFiltering) for the egress allowlist that blocks the metadata and internal destinations, [D3-NTA Network Traffic Analysis](https://d3fend.mitre.org/technique/d3f:NetworkTrafficAnalysis) for the egress-anomaly detection, and [D3-DNSTA DNS Traffic Analysis](https://d3fend.mitre.org/technique/d3f:DNSTrafficAnalysis) for the DNS-rebinding signal.
- Weakness and reference sources: [OWASP A10:2021 Server-Side Request Forgery](https://owasp.org/Top10/A10_2021-Server-Side_Request_Forgery_%28SSRF%29/), CWE-918 (Server-Side Request Forgery), AWS GuardDuty finding types `UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration.OutsideAWS` and `.InsideAWS`, [SigmaHQ rules](https://github.com/SigmaHQ/sigma), and the [Falco default rules](https://github.com/falcosecurity/rules).

**Scope note.** This is a defensive skill. It explains SSRF only to the depth needed to detect and mitigate it and deliberately provides no SSRF payloads, bypass encoders, or metadata-harvesting tooling. UMBRASEC publishes defense, not offense.
