mirror of
https://github.com/fosrl/pangolin.git
synced 2026-07-15 21:31:24 -05:00
[PR #3251] Fix unescaped regex metacharacters in PATH rule matching causing request failures #36915
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
📋 Pull Request Information
Original PR: https://github.com/fosrl/pangolin/pull/3251
Author: @kshitijshresth
Created: 6/12/2026
Status: 🔄 Open
Base:
main← Head:fix-path-rule-regex-escaping📝 Commits (1)
b136bd2Escape regex metacharacters in PATH rule wildcard matching📊 Changes
3 files changed (+193 additions, -207 deletions)
View changed files
➕
server/lib/pathMatch.ts(+74 -0)📝
server/routers/badger/verifySession.test.ts(+117 -70)📝
server/routers/badger/verifySession.ts(+2 -137)📄 Description
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 bycheckRulesinverifySession.tsto evaluate PATH resource rules) converts wildcard pattern segments to regular expressions without escaping regex metacharacters.isValidUrlGlobPatterninvalidators.tsexplicitly 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 buildsnew RegExp("^(api.*$"), which throwsSyntaxError: Invalid regular expression: missing ).checkRuleshas no exception handling, so the error propagates to the catch-all inverifyResourceSessionand every request to that resource fails with500 Failed to verify sessionuntil the rule is deleted.Incorrect matching for literal characters. Since PATH rules commonly gate auth bypass (ACCEPT) or denial (DROP), both directions matter:
*.pngmatchedimageXpng(.acted as regex any-char)a+b*matchedaaabcand failed to matcha+bc(+acted as a quantifier)$ref*could never match anything ($acted as an anchor)Changes
isPathAllowedfromverifySession.tsintopathMatch.tsas a pure module (no logger/config/db imports) so it can be unit tested in isolation;verifySession.tsimports and re-exports it, keeping its public surface unchanged.*→.*and?→.substitutions. The escape set deliberately excludes*and?so wildcard semantics are unchanged.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.logger.debugcalls (~10 string interpolations per segment comparison, evaluated eagerly on every request regardless of log level) were removed.Tests
verifySession.test.tspreviously tested a stale inline duplicate ofisPathAllowedrather than the real implementation, so regressions in the production code could never fail the suite. It now imports the real function frompathMatch.ts.( ) [ ] { } | \ . + ^ $ |as literals, a no-throw guarantee for all characters accepted byisValidUrlGlobPattern, 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.Reproduction (before this fix)
/(api*(accepted by validation).Invalid regular expression: /^(api.*$/: Unterminated groupin logs).🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.