fix(llm-security): compileRules coerces a non-string pattern instead of dropping the rule
new RegExp(pattern, 'i') never throws when pattern is a truthy non-string
(e.g. an object) — it ToString-coerces it first. The truthy-only guard
(`!rule.pattern`) let such a rule through as a real, compiled RegExp,
bypassing the try/catch meant to drop malformed rules. Worse than a silent
drop: `new RegExp("[object Object]", "i")` is parsed as a character class
over o/b/j/e/c/t/space, so the "dropped" rule instead becomes a
near-universal false-positive matcher. Same path for the built-in
commons-backed ruleset and the operator's sig.custom_rules_path (both
route through compileRules).
Fix: require typeof rule.pattern === 'string' before compiling. Verified
the golden dump pins no rule that exists only because of this coercion —
it regenerates byte-identically after the fix.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019iWrdLSVgRhgPzTB29rQGD
This commit is contained in:
parent
eceb71bbb3
commit
f926071348
3 changed files with 63 additions and 5 deletions
|
|
@ -159,5 +159,21 @@ describe('malware-signatures (commons known-bad-identity ruleset)', () => {
|
|||
it('returns an empty array for a ruleset with no rules array', () => {
|
||||
assert.deepEqual(compileRules({}), []);
|
||||
});
|
||||
|
||||
it('drops a rule whose pattern is not a string, instead of stringifying it', () => {
|
||||
// `new RegExp(pattern, 'i')` does not throw when `pattern` is a non-string
|
||||
// object: the RegExp constructor coerces it via ToString, so
|
||||
// `{source: 'x'}` silently becomes the literal pattern "[object Object]"
|
||||
// rather than raising the compile error the `try/catch` below is there to
|
||||
// catch. A truthy-only guard (`!rule.pattern`) lets that coerced rule
|
||||
// through as a real, matching RegExp instead of dropping it.
|
||||
const compiled = compileRules({
|
||||
rules: [
|
||||
{ id: 'OBJ-PATTERN-001', pattern: { source: 'x' } },
|
||||
{ id: 'A', pattern: 'a' },
|
||||
],
|
||||
});
|
||||
assert.deepEqual(compiled.map((r) => r.id), ['A']);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue