#16197: feat(ssrf): enhance protection with comprehensive cloud metadata blocking
stale
size: S
Cluster:
SSRF Protection Enhancements
## Summary
Expand SSRF protection to comprehensively block cloud metadata service endpoints across major providers.
## Problem
The current implementation only blocks `localhost` and `metadata.google.internal`. However, cloud metadata services exist on multiple providers and can be accessed via:
1. Provider-specific hostnames
2. Direct IP addresses (e.g., 169.254.169.254)
3. DNS rebinding attacks that resolve to metadata IPs
Successful SSRF attacks against metadata services can leak:
- Instance credentials (IAM roles, service account tokens)
- Cloud provider configuration
- Sensitive environment variables
- Network topology information
## Solution
### Blocked Hostnames
| Provider | Hostname |
|----------|----------|
| GCP | `metadata.google.internal`, `metadata.goog` |
| AWS | `instance-data` |
| Azure | `metadata.azure.com` |
| Alibaba | `100.100.100.200` |
| DigitalOcean | `metadata.digitalocean.com` |
| Oracle Cloud | `metadata.oraclecloud.com` |
| Kubernetes | `kubernetes.default`, `kubernetes.default.svc` |
### Blocked IP Addresses
| IP | Provider/Purpose |
|----|------------------|
| `169.254.169.254` | AWS, GCP, Azure, DigitalOcean (link-local) |
| `fd00:ec2::254` | AWS IMDSv2 IPv6 endpoint |
| `100.100.100.200` | Alibaba Cloud |
### New Function
Added `isBlockedMetadataIp()` to detect direct IP access:
```typescript
export function isBlockedMetadataIp(address: string): boolean
```
This function:
- Normalizes the input (strips brackets, handles case)
- Handles IPv4-mapped IPv6 addresses (`::ffff:169.254.169.254`)
- Checks against the `BLOCKED_METADATA_IPS` set
### Integration Points
The metadata IP check is called in `resolvePinnedHostnameWithPolicy()`:
1. Before DNS resolution (direct IP access)
2. After DNS resolution (DNS rebinding attacks)
## Security References
- [AWS IMDS](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-retrieval.html)
- [GCP Metadata Server](https://cloud.google.com/compute/docs/metadata/overview)
- [Azure IMDS](https://docs.microsoft.com/en-us/azure/virtual-machines/instance-metadata-service)
- [OWASP SSRF Prevention](https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html)
## Test Plan
- [x] Verify existing localhost/metadata.google.internal blocking still works
- [x] Verify new cloud hostnames are blocked
- [x] Verify 169.254.169.254 is blocked when accessed directly
- [x] Verify DNS resolution to metadata IPs is blocked
- [x] Verify IPv4-mapped IPv6 handling works
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Expands SSRF protection to block cloud metadata service endpoints across major providers (AWS, GCP, Azure, Alibaba, DigitalOcean, Oracle Cloud, Kubernetes). Adds a new `isBlockedMetadataIp()` function for direct IP-based metadata blocking, integrated at both pre-DNS and post-DNS resolution points.
- The new blocked hostnames (`metadata.goog`, `instance-data`, `metadata.azure.com`, `metadata.digitalocean.com`, `metadata.oraclecloud.com`, `kubernetes.default`, `kubernetes.default.svc`) are genuine additions not previously covered.
- The three IPs in `BLOCKED_METADATA_IPS` (`169.254.169.254`, `fd00:ec2::254`, `100.100.100.200`) are all already caught by the existing `isPrivateIpAddress()` function (link-local, private IPv6, and CGNAT ranges respectively), so `isBlockedMetadataIp()` serves as defense-in-depth rather than closing a gap.
- No unit tests were added for the new `isBlockedMetadataIp` function or the expanded hostname list. Given this is security-critical code, test coverage for `isBlockedMetadataIp` (including edge cases like bracket-wrapped IPs and mapped IPv6) would strengthen confidence in the implementation.
<h3>Confidence Score: 4/5</h3>
- This PR is safe to merge — it adds additional SSRF protections without modifying existing behavior.
- The changes are additive and security-hardening. All new blocked IPs are already caught by the existing `isPrivateIpAddress` check, so the new `isBlockedMetadataIp` function provides defense-in-depth. The new blocked hostnames are genuine additions. No existing behavior is modified. The main gap is the absence of unit tests for the new function, which would be expected for security-critical code. Score is 4 rather than 5 due to missing test coverage.
- No files require special attention beyond the minor style issue flagged in `src/infra/net/ssrf.ts`.
<sub>Last reviewed commit: f7e055d</sub>
<!-- greptile_other_comments_section -->
<!-- /greptile_comment -->
Most Similar PRs
#19525: security: add SSRF validation for external URLs
by Mozzzaic · 2026-02-17
84.4%
#8228: fix(link-understanding): block private IPs and internal hostnames i...
by yubrew · 2026-02-03
82.3%
#23598: fix(msteams): add SSRF protection to attachment downloads via redir...
by lewiswigmore · 2026-02-22
74.5%
#11086: fix(mattermost): allow private network for inbound media download
by oskarmodig · 2026-02-07
72.9%
#8305: fix(browser): add SSRF protection to browser navigation
by yubrew · 2026-02-03
72.8%
#23596: fix(msteams): add SSRF validation to file consent upload URL
by lewiswigmore · 2026-02-22
69.1%
#19042: Security: add URL allowlist for web_search and web_fetch
by smartprogrammer93 · 2026-02-17
68.8%
#23312: fix(gateway): strip inbound metadata in chat history sanitization
by SidQin-cyber · 2026-02-22
68.3%
#22756: fix(security): add missing entries to environment variable blocklist
by miloudbelarebia · 2026-02-21
67.6%
#20301: Security: scrub untrusted metadata from user-facing replies
by ashishc2503 · 2026-02-18
67.2%