Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
{
"schema_version": "1.4.0",
"id": "GHSA-rj75-hqrm-r3gf",
"modified": "2026-10-05T22:53:54Z",
"modified": "2026-10-05T22:53:57Z",
"published": "2026-10-05T22:53:54Z",
"aliases": [
"CVE-2026-104844"
],
"summary": "PostCSS: Quadratic complexity in flat selector parsing allows CPU exhaustion",
"details": "### Impact\n\n`.` and `#` are not word delimiters in the tokenizer, so a flat selector such as\n`.a.a.a...` reaches `splitWord()` as a single word token carrying n class or id\nindexes. Three passes scanned those index arrays linearly for every index,\nmaking the parse O(n^2) in the number of indexes rather than in input length:\n`uniqs()`, the `indices.forEach` loop, and the Sass-interpolation filter.\nParsing a 400 KB flat selector took ~34 s on a modern laptop, fully occupying a\nsingle thread. A benign selector of identical byte size parses in tens of\nmilliseconds, so the cost is driven by the index count, not the input size.\nThe nesting depth of such a selector is 0, so the `maxNestingDepth` guard added\nin 7.1.3 offers no protection.\n\nReachability is deployment dependent. Only consumers that parse untrusted,\nattacker-supplied selectors synchronously in a request path are exposed, for\nexample CSS sanitizers, CSS-in-JS services and online playgrounds. Ordinary\nbuild-time use on trusted sources is not affected.\n\n### Patches\n\nFixed in 7.1.6. The three passes now use Set membership tests, making parsing\nlinear in the number of indexes. There is no behaviour change: parsing is\nbyte-identical on a differential corpus of 8413 selectors.\n\n### Workarounds\n\nCap the size of selectors accepted from untrusted sources before parsing.",
"details": "### Impact\n\n`.` and `#` are not word delimiters in the tokenizer, so a flat selector such as\n`.a.a.a...` reaches `splitWord()` as a single word token carrying n class or id\nindexes. Three passes scanned those index arrays linearly for every index,\nmaking the parse O(n^2) in the number of indexes rather than in input length:\n`uniqs()`, the `indices.forEach` loop, and the Sass-interpolation filter.\nParsing a 400 KB flat selector took ~34 s on a modern laptop, fully occupying a\nsingle thread. A benign selector of identical byte size parses in tens of\nmilliseconds, so the cost is driven by the index count, not the input size.\nThe nesting depth of such a selector is 0, so the `maxNestingDepth` guard added\nin 7.1.3 offers no protection.\n\nReachability is deployment dependent. Only consumers that parse untrusted,\nattacker-supplied selectors synchronously in a request path are exposed, for\nexample CSS sanitizers, CSS-in-JS services and online playgrounds. Ordinary\nbuild-time use on trusted sources is not affected.\n\n### Patches\n\nFixed in 7.1.6, and for the 6.x line in 6.1.5 (backport of the same change,\npostcss/postcss-selector-parser#346). The three passes now use Set membership tests, making parsing\nlinear in the number of indexes. There is no behaviour change: parsing is\nbyte-identical on a differential corpus of 8413 selectors.\n\n### Workarounds\n\nCap the size of selectors accepted from untrusted sources before parsing.",
"severity": [
{
"type": "CVSS_V3",
Expand All @@ -25,14 +25,33 @@
"type": "ECOSYSTEM",
"events": [
{
"introduced": "0"
"introduced": "7.0.0"
},
{
"fixed": "7.1.6"
}
]
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "postcss-selector-parser"
},
"ranges": [
{
"type": "ECOSYSTEM",
"events": [
{
"introduced": "0"
},
{
"fixed": "6.1.5"
}
]
}
]
}
],
"references": [
Expand All @@ -44,6 +63,10 @@
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-104844"
},
{
"type": "WEB",
"url": "https://github.com/postcss/postcss-selector-parser/pull/346"
},
{
"type": "WEB",
"url": "https://github.com/postcss/postcss-selector-parser/commit/62b191792df0a0bc56062e5a875bc74aae2a51cd"
Expand All @@ -52,9 +75,17 @@
"type": "PACKAGE",
"url": "https://github.com/postcss/postcss-selector-parser"
},
{
"type": "WEB",
"url": "https://github.com/postcss/postcss-selector-parser/releases/tag/6.1.5"
},
{
"type": "WEB",
"url": "https://github.com/postcss/postcss-selector-parser/releases/tag/7.1.6"
},
{
"type": "WEB",
"url": "https://www.npmjs.com/package/postcss-selector-parser/v/6.1.5"
}
],
"database_specific": {
Expand Down
Loading