What Happened
In 2019, a former AWS employee exploited a server-side request forgery (SSRF) vulnerability in Capital One's web application firewall configuration to access the EC2 instance metadata service. The attacker retrieved temporary security credentials, then used those credentials to access S3 buckets containing over 100 million customer records. Capital One disclosed the breach in July 2019 and later paid $80 million in civil penalties and $190 million in consumer restitution.
The vulnerability existed because Capital One's application accepted user-controlled URLs without proper validation. The attacker crafted requests that forced the server to query AWS's internal metadata endpoint at 169.254.169.254 — an address that should never be reachable from user input.
Timeline
- March 2019: Attacker begins scanning for misconfigured web application firewalls on AWS infrastructure.
- March 22-23, 2019: Attacker successfully exploits SSRF vulnerability in Capital One's environment, retrieves IAM role credentials from metadata service.
- March-July 2019: Using stolen credentials, attacker downloads data from 700+ S3 buckets over several months.
- July 17, 2019: Capital One receives anonymous tip about exposed data.
- July 19, 2019: FBI arrests attacker after finding Capital One data on personal servers.
- July 29, 2019: Capital One publicly discloses breach affecting 106 million customers.
- August 2022: Federal court sentences attacker to time served plus five years supervised release.
Failed or Missing Controls
Input Validation: The application accepted and processed user-supplied URLs without validating the destination. Any URL validation that existed failed to block private IP ranges, link-local addresses (169.254.0.0/16), or localhost references.
Network Segmentation: The application server could reach the EC2 metadata service. In a properly segmented environment, application workloads should not have direct access to infrastructure metadata endpoints.
Least Privilege IAM: The IAM role attached to the compromised instance had overly broad S3 permissions. The credentials the attacker retrieved from the metadata service granted access to hundreds of S3 buckets — far more than the application needed for its function.
Egress Filtering: No controls prevented the application from making outbound requests to internal AWS services or arbitrary external destinations.
Logging and Monitoring: The breach went undetected for four months despite the attacker downloading data from 700+ S3 buckets. Either logging was insufficient or alerts were not configured to detect unusual S3 access patterns from application credentials.
Relevant Standards
OWASP ASVS v4.0.3, Requirement 5.2.6: "Verify that the application validates, sanitizes and encodes user-supplied data to prevent Server-Side Request Forgery (SSRF) attacks." The requirement specifically calls out validating URLs and ensuring applications cannot be used to attack internal services.
PCI DSS v4.0.1, Requirement 6.2.4: "Bespoke and custom software are developed securely" with specific attention to "secure coding techniques" that prevent injection vulnerabilities. The requirement's guidance explicitly includes SSRF as an injection-based vulnerability that must be prevented through input validation.
PCI DSS v4.0.1, Requirement 1.4.2: "Network security controls are configured to restrict connections between untrusted networks and system components in the cardholder data environment." The metadata service should have been unreachable from application-layer code processing untrusted input.
NIST 800-53 Rev 5, Control AC-6 (Least Privilege): "Employ the principle of least privilege, allowing only authorized accesses for users (or processes acting on behalf of users) that are necessary to accomplish assigned organizational tasks." The IAM role violated this by granting access to 700+ S3 buckets when the application likely needed access to fewer than 10.
ISO 27001:2022, Control 8.3 (Information Access Restriction): Organizations must restrict access to information and information processing facilities. The broad S3 permissions and lack of network controls failed this requirement.
Lessons and Action Items for Your Team
Treat Cloud Metadata Services as Hostile Destinations: Add 169.254.169.254/32, 169.254.170.0/23 (for ECS task metadata), and fd00:ec2::254/128 to your URL validation deny lists. If you're using Azure, block 169.254.169.254 and the Azure Instance Metadata Service endpoints. For Google Cloud, block metadata.google.internal.
Implement URL Validation at Multiple Layers: Microsoft's AntiSSRF library, released under the MIT license for .NET and Node.js applications, provides one implementation approach using an AntiSSRFPolicy object to define allowed and denied addresses. Whether you use this library or build your own, your validation must:
- Parse the URL before making any request
- Resolve the hostname to an IP address
- Block private ranges (RFC 1918), link-local addresses, and localhost
- Block DNS rebinding by re-resolving immediately before the request
- Use an allow-list for external destinations when possible
Audit IAM Roles Monthly: Pull the IAM policy for every role attached to compute resources. For each permission, document which application function requires it. If you can't name the function, remove the permission. Capital One's IAM role had access to 700+ buckets. Your application roles should have access to single-digit bucket counts.
Deploy IMDSv2 on All EC2 Instances: AWS's Instance Metadata Service version 2 requires a session token obtained via a PUT request with a specific header. SSRF attacks typically use GET requests and cannot set custom headers, making IMDSv2 resistant to SSRF exploitation. Enable it with aws ec2 modify-instance-metadata-options --instance-id i-xxx --http-tokens required.
Log Metadata Service Access: Enable VPC Flow Logs and create CloudWatch alarms for traffic to 169.254.169.254 from your application subnets. In normal operation, only your configuration management tools should access this endpoint during instance bootstrap.
Test Your Validation: Add these test cases to your security test suite:
http://169.254.169.254/latest/meta-data/iam/security-credentials/http://metadata.google.internal/computeMetadata/v1/http://[::ffff:169.254.169.254]/latest/meta-data/http://2852039166/latest/meta-data/(decimal representation of 169.254.169.254)http://0xa9fea9fe/latest/meta-data/(hex representation)
Your validation must block all of these. If any succeed, you have an SSRF vulnerability.
By integrating these security controls into your development process, you can preemptively mitigate vulnerabilities like SSRF.



