Skip to content

Fix unescaped regex metacharacters in PATH rule matching causing request failures#3251

Open
kshitijshresth wants to merge 1 commit into
fosrl:mainfrom
kshitijshresth:fix-path-rule-regex-escaping
Open

Fix unescaped regex metacharacters in PATH rule matching causing request failures#3251
kshitijshresth wants to merge 1 commit into
fosrl:mainfrom
kshitijshresth:fix-path-rule-regex-escaping

Conversation

@kshitijshresth

Copy link
Copy Markdown

By creating this pull request, I grant the project maintainers an unlimited,
perpetual license to use, modify, and redistribute these contributions under any terms they
choose, including both the AGPLv3 and the Fossorial Commercial license terms. I
represent that I have the right to grant this license for all contributed content.

Summary

isPathAllowed (used by checkRules in verifySession.ts to evaluate PATH resource rules) converts wildcard pattern segments to regular expressions without escaping regex metacharacters. isValidUrlGlobPattern in validators.ts explicitly permits - . _ ~ ! $ & ' ( ) * + , ; # = @ : in rule values, so rules that pass API validation can produce invalid or semantically wrong regexes at request time.

Impact

Unhandled exception on every request. A PATH rule value like /(api* is accepted by validation, but the matcher builds new RegExp("^(api.*$"), which throws SyntaxError: Invalid regular expression: missing ). checkRules has no exception handling, so the error propagates to the catch-all in verifyResourceSession and every request to that resource fails with 500 Failed to verify session until the rule is deleted.

Incorrect matching for literal characters. Since PATH rules commonly gate auth bypass (ACCEPT) or denial (DROP), both directions matter:

  • *.png matched imageXpng (. acted as regex any-char)
  • a+b* matched aaabc and failed to match a+bc (+ acted as a quantifier)
  • $ref* could never match anything ($ acted as an anchor)

Changes

  • Extracted isPathAllowed from verifySession.ts into pathMatch.ts as a pure module (no logger/config/db imports) so it can be unit tested in isolation; verifySession.ts imports and re-exports it, keeping its public surface unchanged.
  • Regex metacharacters are now escaped before the *.* and ?. substitutions. The escape set deliberately excludes * and ? so wildcard semantics are unchanged.
  • Compiled segment regexes are cached in a module-level Map. Keys are admin-defined rule pattern segments (a bounded set), not request paths, so the cache cannot grow with traffic. This avoids recompiling regexes on every proxied request, which sits on the hot path.
  • As part of the extraction, the per-recursion-step logger.debug calls (~10 string interpolations per segment comparison, evaluated eagerly on every request regardless of log level) were removed.

Tests

verifySession.test.ts previously tested a stale inline duplicate of isPathAllowed rather than the real implementation, so regressions in the production code could never fail the suite. It now imports the real function from pathMatch.ts.

  • All pre-existing assertions are unchanged and pass, demonstrating no behavioral change for patterns without metacharacters.
  • Added assertions covering ( ) [ ] { } | \ . + ^ $ | as literals, a no-throw guarantee for all characters accepted by isValidUrlGlobPattern, preserved ? single-character wildcard behavior, and a deep-path sanity check.

Verified against the unfixed logic first: the new tests fail with Invalid regular expression: /^(api.*$/: Unterminated group, and pass after the fix.

npx tsx server/routers/badger/verifySession.test.ts   # all tests pass
npx tsc --noEmit                # clean
npx prettier --check <changed files>   # clean

Reproduction (before this fix)

  1. Create a resource with rules enabled.
  2. Add a PATH rule with value /(api* (accepted by validation).
  3. Every request to the resource now returns 500 (Invalid regular expression: /^(api.*$/: Unterminated group in logs).

isValidUrlGlobPattern accepts characters like ( ) [ ] { } | . + ^ $ in PATH rule values, but isPathAllowed converted wildcard segments to regex without escaping them. A rule value such as /(api* produced an invalid regex and threw on every request to the resource, surfacing as a 500 from verifySession. Literal characters like . and + also changed matching semantics. isPathAllowed is extracted to server/lib/pathMatch.ts as a pure module, metacharacters are escaped before wildcard substitution, compiled segment regexes are cached, and the test suite now imports the real implementation instead of a stale copy, with added coverage for special characters.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant