sts | 68% | 12% | 45% | 3.5 days |
| Allowlist + Adversarial Payload Suite | <1% | 94% | 2% | 2.1 days |
Key Findings:
- Allowlists fail only on explicit misconfiguration, not evasion. Blocklists fail by design due to infinite input space.
- Systematic injection of non-standard IP representations catches library-level bypasses (e.g., CVE-2024-29415) before deployment.
- Response body validation is critical: even when status codes are correctly rejected, leaked metadata in payloads constitutes a credential breach.
- The sweet spot lies in combining strict allowlist enforcement at the application layer with automated adversarial testing pipelines.
Core Solution
Mitigation requires a dual-layer strategy: architectural allowlist enforcement and systematic adversarial testing.
1. Allowlist Architecture
Replace blocklists with explicit destination allowlists. Validate URLs against permitted domains/IPs before resolution. Implement post-resolution IP checks to prevent DNS rebinding attacks. Enforce network segmentation to restrict outbound connectivity from application servers to only required external endpoints.
2. Adversarial SSRF Payload Testing
Every endpoint accepting URLs, hostnames, or IPs must be tested against a curated payload matrix targeting cloud metadata, localhost variants, non-standard representations, and internal ranges.
# Cloud metadata endpoints
http://169.254.169.254/latest/meta-data/ # AWS
http://169.254.169.254/latest/meta-data/iam/security-credentials/
http://metadata.google.internal/computeMetadata/v1/ # GCP
http://169.254.169.254/metadata/instance # Azure
# Localhost variants
http://127.0.0.1/
http://localhost/
http://0.0.0.0/
# Non-standard representations β bypass naive isPublic() checks
http://127.1/ # CVE-2024-29415 bypass
http://0x7f000001/ # hexadecimal
http://2130706433/ # decimal
http://012.0.0.1/ # octal
# Internal network ranges
http://192.168.1.1/
http://10.0.0.1/
http://172.16.0.1/
import pytest
import requests
BASE_URL = "https://your-app.com"
SSRF_PAYLOADS = [
# cloud metadata
"http://169.254.169.254/latest/meta-data/",
"http://169.254.169.254/latest/meta-data/iam/security-credentials/",
"http://metadata.google.internal/computeMetadata/v1/",
"http://169.254.169.254/metadata/instance",
# localhost variants
"http://127.0.0.1/",
"http://localhost/",
"http://0.0.0.0/",
# CVE-2024-29415 bypass patterns β non-standard representations
"http://127.1/",
"http://0x7f000001/",
"http://2130706433/",
"http://012.0.0.1/",
# internal network ranges
"http://192.168.1.1/",
"http://10.0.0.1/",
"http://172.16.0.1/",
]
METADATA_MARKERS = [
"ami-id", "instance-id", "computeMetadata",
"access_key", "secret_access_key", "security-credentials"
]
@pytest.fixture
def auth_session():
session = requests.Session()
session.post(f"{BASE_URL}/login", json={
"username": "testuser",
"password": "test_password"
})
return session
@pytest.mark.parametrize("payload", SSRF_PAYLOADS)
def test_ssrf_payload_rejected(auth_session, payload):
# every internal/cloud address must be rejected β never 200
response = auth_session.post(
f"{BASE_URL}/api/fetch-url",
json={"url": payload}
)
assert response.status_code in [400, 403, 422], (
f"SSRF payload not rejected: {payload} "
f"returned {response.status_code}"
)
@pytest.mark.parametrize("payload", SSRF_PAYLOADS)
def test_ssrf_no_internal_content_in_response(auth_session, payload):
# even if rejected with wrong status, body must not contain metadata
response = auth_session.post(
f"{BASE_URL}/api/fetch-url",
json={"url
3. Implementation Workflow
- Integrate payload matrices into CI/CD pipelines as mandatory gate checks.
- Audit all third-party IP/URL validation libraries for known CVEs and parsing edge cases.
- Enforce response sanitization: strip or mask any internal metadata markers before returning data to clients.
- Restrict cloud instance IAM roles to minimum required permissions; disable IMDSv1 where possible.
Pitfall Guide
- Relying on Blocklists: IP representations are infinite. Blocklists will always have gaps that attackers can exploit through format manipulation.
- Blind Trust in Third-Party Validation Libraries: Functions like
isPublic() contain unresolved edge cases (e.g., CVE-2024-29415). Always verify library behavior against adversarial inputs before deployment.
- Happy-Path Testing Only: Validating that features work correctly does not validate that they reject malicious inputs. SSRF lives exclusively in the adversarial input space.
- Ignoring Non-Standard IP Formats: Hexadecimal, octal, decimal, and shortened IPv4/IPv6 representations bypass naive parsers. Validation must normalize and resolve all formats before enforcement.
- Skipping Response Body Validation: Even when status codes are correctly rejected, leaked metadata in the response body constitutes a credential breach. Always sanitize outputs.
- Static Allowlists Without DNS Rebinding Protection: Domain allowlists can be circumvented if an attacker controls DNS resolution timing. Implement post-resolution IP validation and connection timeouts.
- Over-Permissive Cloud IAM Roles: SSRF exploitation severity scales with instance permissions. Grant minimum required access and enforce IMDSv2 to mitigate metadata harvesting.
Deliverables
- SSRF Defense Blueprint: Architecture diagram detailing allowlist enforcement points, DNS rebinding mitigation strategies, network segmentation boundaries, and cloud metadata access restrictions.
- Pre-Deployment SSRF Checklist: 12-point validation matrix covering payload suite integration, library CVE auditing, response sanitization, IAM role scoping, and CI/CD pipeline gating.
- Configuration Templates: Ready-to-deploy allowlist policy files (Nginx/Envoy examples), PyTest fixture configurations, and automated payload injection scripts for CI/CD integration.