Hall of Fame image from https://openclipart.org/detail/120343/trophy
Back to Hall of Fame Contents Back to Wekan Website

Contents / PatternBleed

CVE Vulnerability name Date Responsible Security Disclosure by Vulnerabilities
-

PatternBleed

2026-08-08 GitHub CodeQL (code scanning alert #431) and xet7 (fix)

Automated code scanning flagged the identity (no-op) replacement.
  • 1. PatternBleed — an escape that escaped nothing: a value went into a regular expression through a no-op replace (CWE-116 Improper Encoding or Escaping of Output)
  • GitHub CodeQL code scanning alert #431, rule js/identity-replacement, severity Medium
  • Affected only the WeKan test suite (tests/releaseNodeSources.test.cjs)
  • Second finding of this rule after IdentityBleed (alert #424), so the fix also adds a guard that catches the whole class in WeKan's own test run
  • Fixed at upcoming WeKan release


Details

1. PatternBleed — an escape that escaped nothing (CWE-116)

A test that checks every platform WeKan builds has a row in the Node.js source-resolver mapping table (tests/releaseNodeSources.test.cjs) built one regular expression per platform name:

// vulnerable — replace('-', '-') is a no-op, so nothing is escaped
const re = new RegExp(`^\s*${p.replace('-', '-')}\)\s+nodename=`, 'm');
    

p.replace('-', '-') replaces a hyphen with a hyphen, so it returns the string unchanged. GitHub CodeQL reports this as js/identity-replacement: replacing a value with itself is almost always a mistake. Its usual cause is a mistyped backslash escape — '\"' in a string literal is simply '"', so replace(/"/g, '\"') is an identity replacement where '\\"' was meant.

What makes this one worth a name rather than a shrug is the position it sat in. It reads as escape this value before interpolating it into a pattern, and it is the only thing standing between a platform name and a new RegExp. The escaping was not merely wrong, it was absent — while looking present. Nothing failed, because the platform names in that list contain only hyphens and a hyphen needs no escaping outside a character class; a name containing ., + or ( would have matched the wrong row, or thrown. There was no runtime exposure: this is test-only code, and the values are a hardcoded list, not user input.

Fix: escape the value for real, with the same helper the other guards in tests/ use:

// fixed — a real escape of every regex metacharacter
const escapeRegExp = str => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
const re = new RegExp(`^\s*${escapeRegExp(p)}\)\s+nodename=`, 'm');
    

The second time, so the class is guarded rather than the instance

This is the second js/identity-replacement finding in WeKan, after IdentityBleed (alert #424) seventeen days earlier. Code scanning finds these after a push, in a web interface, and reports them one at a time. So the fix also adds tests/noIdentityReplacement.test.cjs, which scans WeKan's own JavaScript for the shape and fails in the ordinary test run, in seconds.

Three details decide whether such a guard is worth having:

Verified in both directions: the repository is clean under the guard, and the same scan run against the previous commit reports the offending line.