In early 2023, CVE-2023-24540 was quietly added to major vulnerability databases. At first glance, it looks like “just another JavaScript template bug.” However, its subtlety could have major consequences if not fully understood—especially for anyone building or using server-side rendering or modern frontend frameworks.
This write-up explains CVE-2023-24540 from the ground up. We’ll cover what makes it possible, show code snippets, guide you through exploiting it, and provide you with references for deeper reading.
What Is CVE-2023-24540?
Simply put: CVE-2023-24540 is a sanitization bug in templating systems (like Mustache, Handlebars, etc.) that occur because not all valid JavaScript whitespace characters are treated as whitespace.
Many template engines use a “safe list” of characters when parsing JavaScript code in templates. Most assume that the following are all the whitespace used in JS:
But this is not the full picture.
JavaScript allows dozens of unicode characters to act as whitespace according to its language specification. If a template includes other “uncommon” whitespace and you’re using an escape mechanism/sanitization that only considers the above 7, it might be possible for attackers to sneak malicious code past your security filters.
Why Does This Matter?
If your templating engine parses template sections containing JavaScript, but an attacker can inject unicode whitespace outside the above 7, your sanitization might not recognize the boundary between code and user-provided data.
That can let malicious JavaScript through in user input, exploiting XSS even if your escape functions look robust.
Imagine using an unsafe template setup like this
const template = `<script>
var username = "{{username}}";
// more code...
</script>`
Normally, you’d escape quotes, newlines, etc., in username. But suppose your escaping/sanitization only looks for \t, \n, \f, \r, \u002, \u2028, or \u2029.
An attacker can use unicode whitespace the filter didn’t expect. For instance, unicode character \u00A (NO-BREAK SPACE) or \u168 (OGHAM SPACE MARK):
// Attacker's input (sent through the inputs to the web server):
admin";alert(1);//\u00A
Your sanitizer *misses* the \u00A at the end—it doesn't treat it as the end of the statement or as a boundary—but JS interprets it as whitespace.
What happens in the browser?
// Final rendered HTML in the browser:
<script>
var username = "admin";alert(1);//[NO-BREAK SPACE]
// more code...
</script>
Result: alert(1) pops a JavaScript box—classic XSS!
Let’s show a minimal unsafe sanitizer
function sanitizeUserInput(str) {
// Only strips common whitespace and quote characters
return str.replace(/["'\t\n\f\r\u002\u2028\u2029]/g, '_');
}
But if a user sneaks in other unicode whitespace like \u00A, it isn’t replaced!
Test it
console.log(sanitizeUserInput('malicious\u00Acode'));
// Output: 'malicious_code' (looks safe)
However, inside a <script>, JS will treat that \u00A as a space.
`
hello";alert('XSS');//\u00A
`
2. Templating/sanitizer only checks "normal" whitespace.
</h2><p> var username = "hello";alert('XSS');// <br> // ...<br>
Mitigation & Fixes
- Use complete unicode whitespace list: When filtering JavaScript input or suspicious contexts, be sure your sanitizer recognizes *all* valid JS whitespace, not just the basic set.
- Escape contextually: Use context-sensitive encoding—e.g., HTML-encode for HTML, JS-encode for JS, URL-encode for URLs, etc.
Whitelist content, not blacklist: Instead of blocking known-bad, whitelist what's allowed.
OWASP JavaScript Encoding Cheatsheet offers advice on securely handling JS values in templates.
Technical Resources
- CVE-2023-24540 entry at NVD
- Unicode whitespace in JavaScript (MDN)
- Relevant Github security advisory
- Handbook: ECMAScript White Space
Takeaways
CVE-2023-24540 is a classic example of why security is more than just “find and replace.” Browsers and parsers keep evolving, and Unicode is *always* more complex than you expect. Always keep your dependencies patched, use contextual escaping, and don’t trust “just strip some characters” sanitizers for untrusted code.
If you’re using templates in JS, double-check your sanitization logic today—or attackers might find your whitespace bug for you.
Timeline
Published on: 05/11/2023 16:15:00 UTC
Last modified on: 05/22/2023 18:22:00 UTC