| CVE | Vulnerability name | Date | Responsible Security Disclosure by | Vulnerabilities |
|---|---|---|---|---|
|
-
|
EscapeBleed |
2026-07-17 |
GitHub CodeQL (code scanning alert #423) and xet7 (fix)
![]() Automated code scanning flagged the incomplete escaping. |
|
A regression test that verifies WeKan's maximized-card CSS
(tests/maximizedCardPosition.test.cjs) turned each expected CSS declaration
into a regular expression so it could assert the declaration is present with
!important. To do that it escaped the declaration string before interpolating
it into a RegExp — but the escape only handled parentheses:
// vulnerable — escapes only ( and )
new RegExp(`${decl.replace(/[()]/g, '\\$&')}\\s*!important`).test(m[1]);
A regular-expression metacharacter set includes far more than parentheses:
. * + ? ^ $ { } | [ ] \. Escaping only ( and )
leaves every other metacharacter active, so an input string containing them would be
compiled into a pattern that means something different from the literal text — matching the
wrong thing (a false positive or false negative), and, critically, an input containing a
backslash is not escaped at all. This is the same class of defect as
InputBleed (incomplete sanitization), which CodeQL also flagged.
In this case the input was a fixed, trusted list of CSS declaration strings authored in the
test itself, none of which contain metacharacters, so there was no injection exposure
and the test still passed. The escape was nonetheless genuinely incorrect and would silently
misbehave the moment a declaration containing a metacharacter (for example a value with
. or [) was added.
Fix: escape the complete regular-expression metacharacter set (including the
backslash), matching the correct pattern already used elsewhere in the WeKan tests
(for example tests/archiveLinkGrouping.test.cjs):
// fixed — escapes the full metacharacter set, including backslash
new RegExp(`${decl.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\s*!important`).test(m[1]);
CodeQL rule js/incomplete-sanitization was resolved by this change. The whole
class was swept: the other dynamically-built regular expressions added in the same work
either already escaped the full set or interpolated only fixed identifiers.