- Add comprehensive file type validation to prevent SVG uploads - Update upload widgets to restrict file types at input level - Enhanced HTML sanitization to block SVG tags and data URLs - Create centralized file validation utilities with shared constants - Add client-side and server-side protection against malicious uploads Security Impact: - Prevents stored XSS attacks through malicious SVG profile uploads - Blocks execution of JavaScript embedded in SVG files - Enforces whitelist of safe image formats (JPEG, PNG, GIF, WebP) - Provides defense-in-depth protection across all upload components Fixes reported vulnerability in profile image upload functionality.
67 lines
1.8 KiB
TypeScript
67 lines
1.8 KiB
TypeScript
/**
|
|
* File type validation utilities for preventing malicious uploads
|
|
* Specifically designed to prevent SVG XSS attacks and other security issues
|
|
*/
|
|
|
|
export const ALLOWED_IMAGE_TYPES = [
|
|
'image/jpeg',
|
|
'image/jpg',
|
|
'image/png',
|
|
'image/gif',
|
|
'image/webp'
|
|
] as const;
|
|
|
|
export const ALLOWED_EXTENSIONS = ['.jpg', '.jpeg', '.png', '.gif', '.webp'] as const;
|
|
|
|
/**
|
|
* Validate file type by MIME type
|
|
* @param file - File object to validate
|
|
* @returns boolean indicating if file type is allowed
|
|
*/
|
|
export function validateImageType(file: File): boolean {
|
|
return ALLOWED_IMAGE_TYPES.includes(file.type as any);
|
|
}
|
|
|
|
/**
|
|
* Validate file extension
|
|
* @param filename - Filename to validate
|
|
* @returns boolean indicating if extension is allowed
|
|
*/
|
|
export function validateImageExtension(filename: string): boolean {
|
|
const extension = filename.toLowerCase().substring(filename.lastIndexOf('.'));
|
|
return ALLOWED_EXTENSIONS.includes(extension as any);
|
|
}
|
|
|
|
/**
|
|
* Comprehensive file validation
|
|
* @param file - File object to validate
|
|
* @returns object with validation result and error message
|
|
*/
|
|
export function validateImageUpload(file: File): { isValid: boolean; error?: string } {
|
|
// Check file type
|
|
if (!validateImageType(file)) {
|
|
return {
|
|
isValid: false,
|
|
error: 'Invalid file type. Only JPEG, PNG, GIF, and WebP files are allowed.'
|
|
};
|
|
}
|
|
|
|
// Check file extension (double check for security)
|
|
if (!validateImageExtension(file.name)) {
|
|
return {
|
|
isValid: false,
|
|
error: 'Invalid file extension. Only .jpg, .jpeg, .png, .gif, and .webp files are allowed.'
|
|
};
|
|
}
|
|
|
|
// Additional security checks
|
|
if (file.name.toLowerCase().includes('.svg')) {
|
|
return {
|
|
isValid: false,
|
|
error: 'SVG files are not allowed for security reasons.'
|
|
};
|
|
}
|
|
|
|
return { isValid: true };
|
|
}
|