@@ -2529,6 +2529,16 @@ class EnhancedSecureCryptoUtils {
25292529 throw new Error ( 'Message must be a string' ) ;
25302530 }
25312531
2532+ // Helper function to apply replacement until stable
2533+ function replaceUntilStable ( str , pattern , replacement = '' ) {
2534+ let previous ;
2535+ do {
2536+ previous = str ;
2537+ str = str . replace ( pattern , replacement ) ;
2538+ } while ( str !== previous ) ;
2539+ return str ;
2540+ }
2541+
25322542 // Define all dangerous patterns that need to be removed
25332543 const dangerousPatterns = [
25342544 // Script tags with various formats
@@ -2566,39 +2576,31 @@ class EnhancedSecureCryptoUtils {
25662576 do {
25672577 previousLength = sanitized . length ;
25682578
2569- // Apply all dangerous patterns
2579+ // Apply all dangerous patterns with stable replacement
25702580 for ( const pattern of dangerousPatterns ) {
2571- sanitized = sanitized . replace ( pattern , '' ) ;
2572- }
2573-
2574- // Additional cleanup for edge cases
2575- sanitized = sanitized
2576- // Remove any remaining angle brackets that might form tags
2577- . replace ( / < [ ^ > ] * > / g, '' )
2578- // Remove any remaining protocol handlers
2579- . replace ( / ^ \w + : / gi, '' )
2580- // Remove any remaining event handlers
2581- . replace ( / \b o n \w + \s * = \s * [ " ' ] [ ^ " ' ] * [ " ' ] / gi, '' )
2582- . replace ( / \b o n \w + \s * = \s * [ ^ > \s ] + / gi, '' )
2583- // Remove any remaining dangerous characters
2584- . replace ( / [ < > ] / g, '' )
2585- . trim ( ) ;
2581+ sanitized = replaceUntilStable ( sanitized , pattern ) ;
2582+ }
2583+
2584+ // Additional cleanup for edge cases - each applied until stable
2585+ sanitized = replaceUntilStable ( sanitized , / < [ ^ > ] * > / g) ;
2586+ sanitized = replaceUntilStable ( sanitized , / ^ \w + : / gi) ;
2587+ sanitized = replaceUntilStable ( sanitized , / \b o n \w + \s * = \s * [ " ' ] [ ^ " ' ] * [ " ' ] / gi) ;
2588+ sanitized = replaceUntilStable ( sanitized , / \b o n \w + \s * = \s * [ ^ > \s ] + / gi) ;
2589+
2590+ // Single character removal is inherently safe
2591+ sanitized = sanitized . replace ( / [ < > ] / g, '' ) . trim ( ) ;
25862592
25872593 iterations ++ ;
25882594 } while ( sanitized . length !== previousLength && iterations < maxIterations ) ;
25892595
2590- // Final security pass: remove any remaining potential XSS vectors
2591- sanitized = sanitized
2592- // Remove any remaining HTML-like content
2593- . replace ( / < [ ^ > ] * > / g, '' )
2594- // Remove any remaining protocol handlers
2595- . replace ( / ^ \w + : / gi, '' )
2596- // Remove any remaining event handlers
2597- . replace ( / \b o n \w + \s * = \s * [ " ' ] [ ^ " ' ] * [ " ' ] / gi, '' )
2598- . replace ( / \b o n \w + \s * = \s * [ ^ > \s ] + / gi, '' )
2599- // Remove any remaining dangerous characters
2600- . replace ( / [ < > ] / g, '' )
2601- . trim ( ) ;
2596+ // Final security pass with stable replacements
2597+ sanitized = replaceUntilStable ( sanitized , / < [ ^ > ] * > / g) ;
2598+ sanitized = replaceUntilStable ( sanitized , / ^ \w + : / gi) ;
2599+ sanitized = replaceUntilStable ( sanitized , / \b o n \w + \s * = \s * [ " ' ] [ ^ " ' ] * [ " ' ] / gi) ;
2600+ sanitized = replaceUntilStable ( sanitized , / \b o n \w + \s * = \s * [ ^ > \s ] + / gi) ;
2601+
2602+ // Final single character cleanup
2603+ sanitized = sanitized . replace ( / [ < > ] / g, '' ) . trim ( ) ;
26022604
26032605 return sanitized . substring ( 0 , 2000 ) ; // Limit length
26042606 }
0 commit comments