FRE-4520: Fix security vulnerabilities in notification template system
- Fix HTML injection vulnerability with proper entity encoding - Fix rate limit cleanup bug (count vs timestamp confusion) - Add URL validation to prevent open redirect attacks - Add expiration to in-memory deduplication entries - Use Zod schema for config validation - Add email format validation All 29 tests passing. Ready for Code Reviewer final review. Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
@@ -35,35 +35,39 @@ export const NotificationConfigSchema = z.object({
|
||||
|
||||
export type NotificationConfig = z.infer<typeof NotificationConfigSchema>;
|
||||
|
||||
export const loadNotificationConfig = (): NotificationConfig => ({
|
||||
resend: {
|
||||
apiKey: process.env.RESEND_API_KEY!,
|
||||
baseUrl: process.env.RESEND_BASE_URL || 'https://api.resend.com',
|
||||
},
|
||||
fcm: {
|
||||
privateKey: process.env.FCM_PRIVATE_KEY!,
|
||||
projectId: process.env.FCM_PROJECT_ID!,
|
||||
clientEmail: process.env.FCM_CLIENT_EMAIL!,
|
||||
},
|
||||
apns: {
|
||||
key: process.env.APNS_KEY!,
|
||||
keyId: process.env.APNS_KEY_ID!,
|
||||
teamId: process.env.APNS_TEAM_ID!,
|
||||
bundleId: process.env.APNS_BUNDLE_ID!,
|
||||
},
|
||||
twilio: {
|
||||
accountSid: process.env.TWILIO_ACCOUNT_SID!,
|
||||
authToken: process.env.TWILIO_AUTH_TOKEN!,
|
||||
messagingServiceSid: process.env.TWILIO_MESSAGING_SERVICE_SID!,
|
||||
},
|
||||
rateLimits: {
|
||||
emailPerMinute: parseInt(process.env.EMAIL_RATE_LIMIT || '60', 10),
|
||||
smsPerMinute: parseInt(process.env.SMS_RATE_LIMIT || '30', 10),
|
||||
pushPerMinute: parseInt(process.env.PUSH_RATE_LIMIT || '100', 10),
|
||||
windowSeconds: parseInt(process.env.RATE_LIMIT_WINDOW_SECONDS || '60', 10),
|
||||
},
|
||||
redis: {
|
||||
url: process.env.REDIS_URL || 'redis://localhost:6379',
|
||||
dedupWindowSeconds: parseInt(process.env.DEDUP_WINDOW_SECONDS || '300', 10),
|
||||
},
|
||||
});
|
||||
export const loadNotificationConfig = (): NotificationConfig => {
|
||||
const config = {
|
||||
resend: {
|
||||
apiKey: process.env.RESEND_API_KEY!,
|
||||
baseUrl: process.env.RESEND_BASE_URL || 'https://api.resend.com',
|
||||
},
|
||||
fcm: {
|
||||
privateKey: process.env.FCM_PRIVATE_KEY!,
|
||||
projectId: process.env.FCM_PROJECT_ID!,
|
||||
clientEmail: process.env.FCM_CLIENT_EMAIL!,
|
||||
},
|
||||
apns: {
|
||||
key: process.env.APNS_KEY!,
|
||||
keyId: process.env.APNS_KEY_ID!,
|
||||
teamId: process.env.APNS_TEAM_ID!,
|
||||
bundleId: process.env.APNS_BUNDLE_ID!,
|
||||
},
|
||||
twilio: {
|
||||
accountSid: process.env.TWILIO_ACCOUNT_SID!,
|
||||
authToken: process.env.TWILIO_AUTH_TOKEN!,
|
||||
messagingServiceSid: process.env.TWILIO_MESSAGING_SERVICE_SID!,
|
||||
},
|
||||
rateLimits: {
|
||||
emailPerMinute: parseInt(process.env.EMAIL_RATE_LIMIT || '60', 10),
|
||||
smsPerMinute: parseInt(process.env.SMS_RATE_LIMIT || '30', 10),
|
||||
pushPerMinute: parseInt(process.env.PUSH_RATE_LIMIT || '100', 10),
|
||||
windowSeconds: parseInt(process.env.RATE_LIMIT_WINDOW_SECONDS || '60', 10),
|
||||
},
|
||||
redis: {
|
||||
url: process.env.REDIS_URL || 'redis://localhost:6379',
|
||||
dedupWindowSeconds: parseInt(process.env.DEDUP_WINDOW_SECONDS || '300', 10),
|
||||
},
|
||||
};
|
||||
|
||||
return NotificationConfigSchema.parse(config);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user