Skip to content

perf: rule 941170 moz-binding branch regex slower than v3.3 (1.4–2.5× PCRE regression) #4633

Description

@fzipi

summary

rule 941170 (NoScript InjectionChecker: Attribute Injection) shows a measurable PCRE performance regression in the v4 line vs v3.3 on benign inputs. the cause is a single sub-pattern change in the moz-binding alternation branch, introduced in PR #2292 (Nov 2021) and never backported to v3.3.

affected versions

  • regression present: v4.0.0 → v4.25.0 (current main/4.27.0-dev)
  • not affected: v3.3.0 → v3.3.9

root cause

the moz-binding branch of the rule's regex changed as follows:

version fragment
v3.3.x \W*?-\W*?m\W*?o\W*?z\W*?-\W*?b\W*?i\W*?n\W*?d\W*?i\W*?n\W*?g[\s\S]*?:[\s\S]*?\W*?u\W*?r\W*?l[\s\S]*?\(
v4.x [^-]*?-\W*?m\W*?o\W*?z\W*?-\W*?b\W*?i\W*?n\W*?d\W*?i\W*?n\W*?g[^:]*?:\W*?u\W*?r\W*?l[\s\S]*?\(

two changes were made:

  1. \W*?-[^-]*?-this is the regression source. \W matches only non-word chars; [^-] matches everything except - (including all word chars). combined with the outer (?:\W|^) start anchor (which retries at every non-word boundary) and the chained \W*? separators following it, the engine backtracks across a much larger search space on benign long inputs that contain a - somewhere.
  2. [\s\S]*?:[\s\S]*?[^:]*?: — this is not the regression; it's a small fail-fast improvement and should be kept.

PR #2292 has no description, no rationale, and no tests. the 941170 test file (tests/regression/tests/REQUEST-941-APPLICATION-ATTACK-XSS/941170.yaml) has zero tests covering the moz-binding sub-branch, so the change isn't load-bearing for any documented coverage.

measurements

PCRE benchmark via Perl, 200 iterations per long input:

input v3.3 v4.25 regression
("a" x 2048) . "-x" (one dash near end) 0.046s 0.115s 2.5×
UA-like header w/ many dashes (840 B) 0.016s 0.026s 1.7×
query string w/ many dashes (2404 B) 0.048s 0.067s 1.4×
benign 4608 B w/ many dashes interleaved 0.096s 0.128s 1.3×
short benign / no-dash inputs n/a n/a none
positive -moz-binding match 0.003s 0.003s none

reproduction script available on request.

proposed fix

revert only the regression-introducing fragment ([^-]*?-\W*?-), keep the [^:]*?: improvement:

- |[^-]*?-\W*?m\W*?o\W*?z\W*?-\W*?b\W*?i\W*?n\W*?d\W*?i\W*?n\W*?g[^:]*?:\W*?u\W*?r\W*?l[\s\S]*?\(
+ |\W*?-\W*?m\W*?o\W*?z\W*?-\W*?b\W*?i\W*?n\W*?d\W*?i\W*?n\W*?g[^:]*?:\W*?u\W*?r\W*?l[\s\S]*?\(

restores v3.3 perf on every measured input, no regression on positive matches. the rule's transformation chain (utf8toUnicode, urlDecodeUni, htmlEntityDecode, jsDecode, cssDecode) already normalizes encoded variants, so \W*? is sufficient by the time the regex sees the input.

refs

ai disclosure

  • tools used: Claude (Opus 4.7)
  • assisted with: regex diffing across versions, PCRE microbenchmark scaffolding, issue body drafting
  • review performed: manually verified diff between v3.3.9 and v4.25.0 rule files, ran the benchmark locally and confirmed numbers, cross-checked PR fix 941170 #2292 patch and absence of tests/description, confirmed test file has no moz-binding coverage

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions