-
Notifications
You must be signed in to change notification settings - Fork 232
Open
Description
Description
Juice hangs indefinitely with 100% CPU usage when processing CSS containing the :is() pseudo-class with comma-separated selectors.
The root cause is that mensch (the CSS parser used by juice) incorrectly parses these selectors, which then causes slick to hang.
While I haven't tested for other pseudo selectors but I suspect it should fail there too.
Reproduction
CodeSandbox
🔗 Live reproduction: [Codesandbox]
Code Example
const html = `<!DOCTYPE html>
<html>
<head>
<style>
.random-jshg5 .ShadowHTML :is(.styleUnquotedContent .unquoted-content, .styleUnquotedContent .sh-unquoted-content) {
font-color: red !important;
}
</style>
</head>
<body>
<div class="random-jshg5">
<div class="ShadowHTML">
<div class="styleUnquotedContent">
<div class="unquoted-content">
<td class="column-container">Content should have font-size: 0</td>
</div>
</div>
</div>
</div>
</body>
</html>`;
// This hangs indefinitely with 100% CPU usage
const result = juice(html);
Root Cause Analysis
The bug occurs in the following chain:
- Juice uses mensch to parse CSS (lib/utils.js:61)
var parsed = mensch.parse(css, {position: true, comments: true});- mensch incorrectly parses
:is()selectors: mensch treats the comma inside:is(.a, .b)as a selector separator, splitting it into multiple selectors instead of keeping it as one complete selector - mensch outputs malformed selector: The parsed result contains only the partial selector
:is(.a(missing closing parenthesis) - Juice passes this to slick: The malformed selector is then passed to slick for processing
- slick hangs on malformed selector: The unclosed parenthesis causes catastrophic backtracking in slick's regex, resulting in an infinite loop
When CSS contains:
:is(.styleUnquotedContent .unquoted-content, .styleUnquotedContent .sh-unquoted-content)mensch parses this as two separate selectors:
:is(.styleUnquotedContent .unquoted-content.styleUnquotedContent .sh-unquoted-content)
Instead of one complete selector.
Impact
- Makes juice completely unusable with modern CSS
- Causes denial of service (100% CPU, process hang)
- Browser tab freezes (in browser environment)
The mensch parser appears to be unmaintained and lacks support for modern CSS syntax.
Migrating to a more robust engine like css or postcss would ensure better compatibility with current CSS standards and prevent parsing failures.
Metadata
Metadata
Assignees
Labels
No labels