/** * Input Sanitization Utilities * Protects against XSS, prompt injection, and other injection attacks */ import createDOMPurify from 'dompurify' import {JSDOM} from 'jsdom' const window = new JSDOM('').window const DOMPurify = createDOMPurify(window as any) // DOMPurify config for strict sanitization const PURIFY_CONFIG = { ALLOWED_TAGS: [], // No HTML tags allowed ALLOWED_ATTR: [], // No attributes allowed KEEP_CONTENT: true // Keep text content } /** * Sanitize user input to remove HTML/JS * Use for: Issue comments, PR descriptions, user-generated content */ export const sanitizeHTML = (input: string): string => { if (!input) return '' return DOMPurify.sanitize(input, PURIFY_CONFIG) } /** * Escape special regex characters * Use for: Preventing regex injection */ export const escapeRegex = (input: string): string => { return input.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') } /** * Escape shell command arguments * Use for: Preventing command injection in exec calls */ export const escapeShellArg = (arg: string): string => { // Remove null bytes and escape quotes return arg.replace(/\x00/g, '').replace(/["'`]/g, '') } /** * Sanitize AI prompt input * Prevents prompt injection attacks */ export const sanitizePrompt = (input: string): string => { if (!input) return '' // Remove common prompt injection patterns const dangerousPatterns = [ /ignore previous instructions/gi, /disregard (the|all|any) (above|previous|prior)/gi, /system prompt/gi, /you are now/gi, /new instructions/gi, /===END.*===/gi, // Pattern markers /<\|endoftext\|>/gi, // GPT end markers /\[SYSTEM\]/gi, /\[INSTRUCTION\]/gi, /\[PROMPT\]/gi ] let sanitized = input for (const pattern of dangerousPatterns) { sanitized = sanitized.replace(pattern, '[REDACTED]') } // Also apply HTML sanitization return sanitizeHTML(sanitized) } /** * Sanitize filename/path input * Prevents path traversal attacks */ export const sanitizePath = (input: string): string => { if (!input) return '' // Remove path traversal patterns return input .replace(/\.\./g, '') // Remove parent directory references .replace(/^[\/\\]/, '') // Remove leading slashes .replace(/\x00/g, '') // Remove null bytes } /** * Validate and sanitize webhook payload */ export const sanitizeWebhookPayload = (payload: any): any => { if (typeof payload !== 'object' || payload === null) { return payload } const sanitized: any = {} for (const [key, value] of Object.entries(payload)) { if (typeof value === 'string') { // Sanitize string values sanitized[key] = sanitizeHTML(value) } else if (typeof value === 'object' && value !== null) { // Recursively sanitize nested objects sanitized[key] = sanitizeWebhookPayload(value) } else { // Keep primitives as-is sanitized[key] = value } } return sanitized } /** * Rate limiting helper for sanitization * Prevents ReDoS attacks on regex sanitization */ export const safeSanitize = ( input: string, sanitizer: (s: string) => string, maxLength = 100000 ): string => { if (!input) return '' // Truncate very long inputs to prevent ReDoS const truncated = input.length > maxLength ? input.substring(0, maxLength) + '... [truncated]' : input return sanitizer(truncated) }