Lesson 14 of 15Security and Abuse Prevention

Security and Abuse Prevention

Notification systems touch email addresses, phone numbers, device tokens, invoices, login alerts, and provider credentials. They also cost money. That makes them attractive to attackers.

Threats

Email spoofingSMS OTP abuseProvider API key leakageWebhook forgeryTemplate injectionNotification spamSensitive data in logsOpen redirect deep links

API Authentication

Only trusted services should create notifications.

app.post("/notifications", authenticateServiceToken, async (req, res) => {
  await notificationService.create(req.body);
  res.status(202).json({ accepted: true });
});

Use service-to-service auth, scoped API keys, or mTLS depending on the environment. Do not expose a general send endpoint to browsers.

Rate Limiting

Rate limit expensive or sensitive operations.

OTP by phone
3 / 10 minutes
OTP by IP
20 / hour
SMS by tenant
budget limit / day
Email by user
product activity digest limits

Rate limits should be visible in monitoring. Silent drops are hard to debug.

Secret Management

Provider keys should live in a secrets manager or secure environment variables. Rotate keys. Restrict permissions. Separate staging and production provider accounts.

Never log provider secrets or full authorization headers.

Webhook Validation

Providers send delivery events. Attackers can fake webhooks unless you verify signatures.

function verifyProviderWebhook(rawBody: string, signature: string) {
  const expected = createHmac("sha256", process.env.PROVIDER_WEBHOOK_SECRET!)
    .update(rawBody)
    .digest("hex");

  return timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

Use the raw request body. Parsing and re-stringifying JSON can change the bytes and break verification.

Email Spoofing

Configure:

SPF
Which servers can send mail
DKIM
Cryptographic signature
DMARC
Policy for failed checks

Without these, attackers can impersonate your domain more easily, and providers may mark legitimate mail as suspicious.

Template Injection

Escape variables. Do not allow arbitrary HTML from user input in templates.

const safeName = escapeHtml(user.name);

If a notification includes a user comment, render it as text, not trusted HTML.

Signed URLs

Invoices, exports, and private files should use expiring signed URLs.

Signed URL
https://cdn.example.com/invoices/inv_123.pdf?signature=...&expires=...

Do not put permanent private file URLs in emails.

Notifications often move sensitive data outside your app. Design them with the same care as APIs.

Common Mistakes

  1. Exposing notification creation to untrusted clients.
  2. Not verifying provider webhooks.
  3. Storing raw OTPs or secrets in logs.
  4. Including sensitive data in push payloads.
  5. Sending private files through permanent URLs.

Interview Questions

  1. How do you prevent SMS OTP abuse?
  2. Why must webhook signatures use the raw body?
  3. What do SPF, DKIM, and DMARC do?
  4. What data should not be included in push payloads?

Exercise

Write a security checklist for a password reset notification flow, including rate limits, token expiry, email content, and logging rules.

What you will learn

How attackers abuse notification systems.

How to protect provider credentials and webhooks.

How rate limits reduce SMS and OTP fraud.

How email spoofing and signed URLs are handled.

Production checklist

  • API access is authenticated
  • Secrets are stored securely
  • Provider webhooks are verified
  • Rate limits exist
  • PII is minimized
  • Signed URLs expire