Skip to content

Commit 0d7835c

Browse files
committed
fix: resolve incomplete multi-character sanitization in sanitizeMessage
Use stable replacement loop for all multi-character patterns to prevent malicious input from reappearing after sanitization.
1 parent 7604381 commit 0d7835c

File tree

3 files changed

+51
-33
lines changed

3 files changed

+51
-33
lines changed

dist/app-boot.js

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2760,6 +2760,14 @@ var EnhancedSecureCryptoUtils = class _EnhancedSecureCryptoUtils {
27602760
if (typeof message !== "string") {
27612761
throw new Error("Message must be a string");
27622762
}
2763+
function replaceUntilStable(str, pattern, replacement = "") {
2764+
let previous;
2765+
do {
2766+
previous = str;
2767+
str = str.replace(pattern, replacement);
2768+
} while (str !== previous);
2769+
return str;
2770+
}
27632771
const dangerousPatterns = [
27642772
// Script tags with various formats
27652773
/<script\b[^>]*>[\s\S]*?<\/script\s*>/gi,
@@ -2793,12 +2801,20 @@ var EnhancedSecureCryptoUtils = class _EnhancedSecureCryptoUtils {
27932801
do {
27942802
previousLength = sanitized.length;
27952803
for (const pattern of dangerousPatterns) {
2796-
sanitized = sanitized.replace(pattern, "");
2804+
sanitized = replaceUntilStable(sanitized, pattern);
27972805
}
2798-
sanitized = sanitized.replace(/<[^>]*>/g, "").replace(/^\w+:/gi, "").replace(/\bon\w+\s*=\s*["'][^"']*["']/gi, "").replace(/\bon\w+\s*=\s*[^>\s]+/gi, "").replace(/[<>]/g, "").trim();
2806+
sanitized = replaceUntilStable(sanitized, /<[^>]*>/g);
2807+
sanitized = replaceUntilStable(sanitized, /^\w+:/gi);
2808+
sanitized = replaceUntilStable(sanitized, /\bon\w+\s*=\s*["'][^"']*["']/gi);
2809+
sanitized = replaceUntilStable(sanitized, /\bon\w+\s*=\s*[^>\s]+/gi);
2810+
sanitized = sanitized.replace(/[<>]/g, "").trim();
27992811
iterations++;
28002812
} while (sanitized.length !== previousLength && iterations < maxIterations);
2801-
sanitized = sanitized.replace(/<[^>]*>/g, "").replace(/^\w+:/gi, "").replace(/\bon\w+\s*=\s*["'][^"']*["']/gi, "").replace(/\bon\w+\s*=\s*[^>\s]+/gi, "").replace(/[<>]/g, "").trim();
2813+
sanitized = replaceUntilStable(sanitized, /<[^>]*>/g);
2814+
sanitized = replaceUntilStable(sanitized, /^\w+:/gi);
2815+
sanitized = replaceUntilStable(sanitized, /\bon\w+\s*=\s*["'][^"']*["']/gi);
2816+
sanitized = replaceUntilStable(sanitized, /\bon\w+\s*=\s*[^>\s]+/gi);
2817+
sanitized = sanitized.replace(/[<>]/g, "").trim();
28022818
return sanitized.substring(0, 2e3);
28032819
}
28042820
// Generate cryptographically secure salt (64 bytes for enhanced security)

dist/app-boot.js.map

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/crypto/EnhancedSecureCryptoUtils.js

Lines changed: 30 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -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(/\bon\w+\s*=\s*["'][^"']*["']/gi, '')
2582-
.replace(/\bon\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, /\bon\w+\s*=\s*["'][^"']*["']/gi);
2588+
sanitized = replaceUntilStable(sanitized, /\bon\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(/\bon\w+\s*=\s*["'][^"']*["']/gi, '')
2598-
.replace(/\bon\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, /\bon\w+\s*=\s*["'][^"']*["']/gi);
2600+
sanitized = replaceUntilStable(sanitized, /\bon\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

Comments
 (0)