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 spoofing
SMS OTP abuse
Provider API key leakage
Webhook forgery
Template injection
Notification spam
Sensitive data in logs
Open 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.
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
- Exposing notification creation to untrusted clients.
- Not verifying provider webhooks.
- Storing raw OTPs or secrets in logs.
- Including sensitive data in push payloads.
- Sending private files through permanent URLs.
Interview Questions
- How do you prevent SMS OTP abuse?
- Why must webhook signatures use the raw body?
- What do SPF, DKIM, and DMARC do?
- 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