
The CVE that prompted this post was not unusual in its origin. An application accepted a URL from users a legitimate feature, for fetching remote content to display or process. The URL was not validated against an allowlist. The server made an outbound HTTP request to whatever URL was provided. SSRF. The finding was scored at medium severity by the vendor, on the reasoning that the server could only make GET requests and could not directly access the internet-exposed attack targets that most people associate with critical impact.
The vendor was correct that the direct impact was limited. They were wrong that the vulnerability was medium severity. Within three weeks of the CVE disclosure, a complete SSRF-to-RCE exploit chain was published. Within six weeks, the exploit was observed in active campaigns against organizations that had not yet patched. Several of those organizations had specifically triaged the CVE as non-urgent based on the medium scoring.
This post is a technical breakdown of how that chain worked, generalized into the exploit pattern it represents, and what it means for how SSRF vulnerabilities should be evaluated and patched.
Stage One: SSRF Confirmed - The Initial Finding
The vulnerability was in a webhook preview feature. The application allowed users to configure webhook endpoints by providing a URL. Before saving the configuration, the application fetched the URL and displayed the response to confirm the endpoint was reachable. The request was made server-side.
The confirmation of SSRF was straightforward: replace the webhook URL with a URL pointing to a known SSRF testing service, observe the inbound request at the testing service, confirm the server's IP address as the source. SSRF confirmed.
At this point, the finding was classified as an information disclosure: the attacker could cause the application server to make GET requests to arbitrary URLs. The attacker could learn the server's external IP address. They could use the server as a proxy for requests to other external systems, potentially bypassing IP-based blocklists. They could potentially map some internal network topology if internal services responded to GET requests with distinguishable responses.
Moderate impact. Medium scoring. The vendor's initial assessment was not unreasonable given only this information.
What it missed: the internal network context.

Stage Two: Cloud Metadata Service - The Credential Grab
The application ran on a cloud provider. Cloud metadata services the internal HTTP endpoints that virtual machines can query to retrieve instance metadata, including IAM credentials are the first and most impactful SSRF pivot for any cloud-hosted application.
AWS's metadata service lives at 169.254.169.254. GCP's at metadata.google.internal and 169.254.169.254. Azure's at 169.254.169.254 (link-local, same address). These are non-routable link-local addresses, reachable only from within the instance. They are not accessible from the internet. They are accessible from the application server.
The SSRF reached them.
Webhook URL: http://169.254.169.254/latest/meta-data/
The application server fetched this URL and returned the response in the webhook preview. The response was the AWS instance metadata index a list of paths beneath the metadata service root. The attacker proceeded methodically:
The final request returned a JSON object containing an AccessKeyId, a SecretAccessKey, and a Token. Temporary IAM credentials for the EC2 instance's attached role.
The fetch happened in the application's webhook preview feature. The response was displayed to the attacker in the application's UI, because the feature was designed to show the webhook endpoint's response. The credentials were displayed in plain text in a text box on a settings configuration page.

The attacker now had IAM credentials for the EC2 instance's role. The next step was determining what those credentials were permitted to do.
Stage Three: IAM Permission Enumeration - Mapping the Privilege
With temporary IAM credentials, the attacker had authenticated access to AWS APIs the same access the application server had been configured with. The scope of that access depended on the IAM role attached to the instance, which the attacker could enumerate without needing administrative IAM permissions.
AWS IAM policy evaluation follows a specific model. Without the ability to call iam:GetRolePolicy, the attacker cannot directly read the role's policies. But they can enumerate effective permissions by attempting actions and observing which succeed and which return access denied.
Tools like enumerate-iam (a publicly available Python script) automate this enumeration: they attempt hundreds of AWS API calls across all service namespaces and report which return successful responses. In a well-constrained IAM role, most calls fail. In a role that was created with broad permissions "to make things work," many succeed.
In this specific case, the enumeration revealed:
ec2:DescribeInstances- the attacker could list all EC2 instances in the accountec2:DescribeSecurityGroups- the attacker could map the network security groupss3:ListAllMyBucketsands3:GetObjecton specific bucket ARNs - the attacker could read application data stored in S3ssm:StartSessionandssm:SendCommand- the attacker could execute commands on instances via AWS Systems Manager
The ssm:SendCommand permission was the pivot to RCE. AWS Systems Manager Session Manager allows executing shell commands on EC2 instances without requiring SSH access or public IP exposure. It is the "you should not need a bastion host" feature. It also, when attached to an instance role with misconfigured IAM policies, is a remote code execution primitive accessible to anyone with valid IAM credentials.

Stage Four: Internal Network Discovery via SSRF
While the IAM credential chain was the most direct path to RCE, the attacker also used the SSRF to map the internal network information that opened additional attack paths and that illustrated the reconnaissance value of SSRF independent of the metadata service.
Internal service discovery through SSRF works by probing internal IP addresses and ports for responses:
http://10.0.0.1:8080/
http://10.0.0.1:9090/
http://10.0.1.5:8500/
Responses fall into three categories: connection refused (the port is closed or no service is listening), timeout (the IP does not respond either filtered or non-existent), and a successful HTTP response (a service is listening and responding). The attacker iterates through internal IP ranges and common service ports, using the SSRF to probe the network.
In this environment, the probe revealed:
A Consul service discovery endpoint at 10.0.1.5:8500 - Consul is a service mesh and configuration tool that maintains a registry of all services in the environment. The Consul UI was accessible without authentication and listed every service by name, every service instance by IP and port, and the health status of each. The attacker now had a complete internal service inventory.
A Kubernetes dashboard at 10.0.2.10:8001 - deployed without authentication during an internal hackathon and never removed from the internal network. The dashboard had cluster-admin access and provided full control over Kubernetes workloads.
An internal Jenkins instance at 10.0.3.20:8080 - accessible without authentication, containing pipeline configurations that included hardcoded credentials for the production database, the production AWS account, and several third-party service APIs.

Stage Five: RCE Multiple Simultaneous Paths
By Stage Four, the attacker had multiple independent paths to remote code execution, each discovered through the initial SSRF.
Path 1: SSM SendCommand. Using the IAM credentials obtained from the metadata service, the attacker called ssm:SendCommand with a shell command targeting the production application instances. The command executed on the EC2 instances running the application. One API call. Full shell access to production compute.
Path 2: Kubernetes Dashboard. The unauthenticated Kubernetes dashboard provided UI-based access to create, modify, and delete Kubernetes workloads. The attacker could deploy a new pod with a container image of their choice, mounted with the host filesystem, providing read-write access to the underlying node. This is a well-documented Kubernetes escape technique available when the dashboard has cluster-admin access.
Path 3: Jenkins pipeline execution. The unauthenticated Jenkins instance contained pipeline configurations that could be triggered directly. Triggering an existing pipeline that deployed code to production would execute arbitrary commands in the deployment environment. Modifying a pipeline configuration to include a malicious step would execute arbitrary commands in a context with credentials for every system in the environment.
Any one of these paths was sufficient for full compromise. All three existed simultaneously. The attacker chose the SSM path for clean, low-noise execution it left less forensic evidence than Kubernetes workload manipulation and did not require creating new artifacts in Jenkins.

The Patch Timeline: Where It Went Wrong
The CVE was publicly disclosed with a medium severity rating. The vendor released a patch. Organizations received the vulnerability notification through their standard CVE monitoring channels.
Week 1 post-disclosure: Most organizations with formal vulnerability management programs triage the CVE. Medium severity, authentication required to trigger, server-side only GET requests. Patch scheduled for the next maintenance window three to four weeks out. Organizations with critical CVE patching SLAs of 30 days slot it for day 28.
Week 2 post-disclosure: Security researchers publish the metadata service pivot. The CVE is reclassified in several vulnerability intelligence feeds. Some organizations update their triage to high severity and move the patch timeline up. Others do not receive the re-triage signal because their vulnerability intelligence workflow does not track post-disclosure research.
Week 3 post-disclosure: A full proof-of-concept exploit chain is published SSRF to metadata credentials to SSM RCE as a public GitHub repository with a working script. The CVE is re-rated in most major vulnerability databases. The vendor issues an updated advisory urging urgent patching.
Week 4 post-disclosure: Active exploitation begins. Automated scanning tools incorporate the exploit chain. Organizations still running unpatched instances those that scheduled patching for day 28 based on the initial medium severity score begin receiving intrusion indicators.
Week 6 post-disclosure: Several organizations confirm compromise. Post-mortems reveal that the initial SSRF was confirmed by their own security teams during routine scanning, triaged as medium severity based on the published score, and scheduled for remediation that had not yet occurred when the active exploitation began.

Why SSRF Scoring Consistently Underrepresents Real Impact
The fundamental problem in how SSRF CVEs are scored is that the base CVSS score represents the vulnerability in isolation what the SSRF can do directly, without considering what the SSRF can reach.
CVSS calculates the attack vector, the complexity, the privileges required, and the impact on confidentiality, integrity, and availability. For an SSRF vulnerability, the direct impact is "the server makes a request to an arbitrary URL." The direct impact on confidentiality is the information returned by whatever that URL responds with. In a vacuum assuming no internal services, no cloud metadata services, no sensitive endpoints reachable from the server the impact is genuinely medium.
In the real deployment environment of almost every cloud-hosted application, the SSRF can reach the metadata service. This changes the impact profile dramatically. The metadata service returns IAM credentials. IAM credentials have permissions that were configured by the operations team without contemplating what would happen if those credentials were stolen via SSRF. The permissions frequently include capabilities that enable further escalation.
The CVSS base score captures the first step of the chain. The environmental score which adjusts for the specific deployment context is where the actual risk lives. Environmental scoring requires the consuming organization to assess their own deployment, which requires knowing that the metadata service is reachable, that the IAM role has the permissions it has, and that the internal network has the services it has.
Most organizations do not perform this environmental assessment. They consume the base score, schedule the patch accordingly, and discover the actual impact when the exploit chain arrives.
The Defender's Countermeasures: What Should Have Been in Place
The chain in this post had multiple points where defensive controls would have interrupted it.
SSRF prevention at the application layer. The webhook preview feature should have validated the provided URL against an explicit allowlist of permitted domains the domains where legitimate webhook endpoints would be configured before making the server-side request. If the URL was not on the allowlist, the request should not have been made. This eliminates the SSRF entirely.
Metadata service protection. AWS IMDSv2 requires an additional PUT request with a session-orientation header before the metadata service will respond. An SSRF that makes GET-only requests cannot satisfy this requirement. Enforcing IMDSv2 on all EC2 instances prevents metadata credential theft via GET-only SSRF. This was available as a configuration option; it was not enabled.
Least-privilege IAM roles. The EC2 instance's IAM role should contain only the permissions the application legitimately requires: read access to the specific S3 paths it uses, specific DynamoDB table access, specific API Gateway permissions. ssm:SendCommand and ssm:StartSession are not required for a web application. They should not have been in the role.
Internal service authentication. Consul, the Kubernetes dashboard, and Jenkins should not have been accessible without authentication on an internal network. The assumption that internal means trusted is the architectural premise that made the internal service discovery phase of the attack as productive as it was.
SSRF-aware HTTP clients. SSRF-safe HTTP client libraries are available for most languages. They resolve the destination IP address before making the request and reject connections to private IP ranges, loopback addresses, and link-local addresses. Configuring the webhook preview feature to use a SSRF-aware HTTP client would have prevented the metadata service pivot even if the URL validation was absent.

The Lessons That Travel Beyond This CVE
This specific SSRF-to-RCE chain is no longer novel. The CVE is patched. Organizations that were going to be compromised via this specific vulnerability largely have been. But the lessons from the chain travel to every SSRF vulnerability found in a cloud-hosted application.
SSRF in cloud environments is a metadata service attack until proven otherwise. The default assumption for any confirmed SSRF in a cloud-hosted application should be: does this reach 169.254.169.254? If yes, what are the permissions of the attached IAM role, service account, or managed identity? The initial CVSS score should not be the ceiling for your impact assessment. The metadata service reachability is the floor.
Exploit chains publish before patches complete. The gap between CVE disclosure and working public exploit is measured in weeks, not months, for vulnerabilities with clear escalation paths. Vulnerability management programs that schedule patches based on disclosure severity without tracking post-disclosure research are operating on incomplete information.
Internal networks are not trust boundaries. Every unauthenticated internal service is a potential pivot point for an SSRF attacker who can reach internal IP ranges. The Kubernetes dashboard, the Consul registry, the Jenkins instance these were not exposed to the internet. They were exposed to any process running inside the network perimeter, including a compromised application server exploited via SSRF.
IMDSv2 enforcement is not optional. For every cloud-hosted application that makes outbound HTTP requests for any reason, enforcing IMDSv2 on the underlying compute is a critical control. It takes one configuration change per instance or instance launch template. It breaks the most common and most impactful SSRF escalation path in cloud environments. It should be a baseline requirement, not a recommendation.
Closing: The Chain Was Available the Moment the SSRF Was
The attacker who exploited this vulnerability did not build anything. They followed a chain that was available the moment the SSRF was confirmed. The metadata service was always reachable. The IAM role always had those permissions. The internal services were always unauthenticated. The SSM access was always possible.
The SSRF was the key that opened the first door. Everything behind the first door was already as exploitable as it was going to be. The chain existed in the environment from the day the application was deployed. The SSRF made it accessible.
This is the correct mental model for evaluating SSRF vulnerabilities: not "what can the SSRF do directly?" but "what can the SSRF reach, and what can be done from there?" The first question produces a medium severity score. The second question produces the correct severity assessment.
The medium severity score scheduled the patch for week four. The correct severity assessment would have scheduled it for week one. The breach happened in week five.
The patch was always going to be the same patch. The question was only whether it would be applied before or after the chain was followed.
Axeploit tests SSRF vulnerabilities for exploitability in context not just whether the server makes an outbound request, but whether that request can reach the cloud metadata service, whether the metadata service returns credentials, and what permissions those credentials carry. It traces SSRF through the escalation path that determines actual impact rather than stopping at the initial request confirmation. A confirmed SSRF finding from Axeploit includes the reachability assessment for internal services and metadata endpoints the information that determines whether "SSRF confirmed" means medium severity or critical.





