Skip to content

fix: ** glob matches greedily, ignoring trailing template segments - #15

Open
I3eg1nner wants to merge 3 commits into
oboard:mainfrom
I3eg1nner:fix/cwe862-wildcard-bypass
Open

fix: ** glob matches greedily, ignoring trailing template segments#15
I3eg1nner wants to merge 3 commits into
oboard:mainfrom
I3eg1nner:fix/cwe862-wildcard-bypass

Conversation

@I3eg1nner

Copy link
Copy Markdown
Contributor

The ** wildcard in route templates consumes all remaining path segments
without checking what follows in the template. /admin/**/settings
matches /admin/anything — the /settings suffix is silently ignored.

Root cause: match_path_segments was greedy (grab everything, return).
The trie has the same problem — DynamicRouteTrieNode::insert sees **,
stores a DeepWildcard handler, and returns, discarding trailing segments.

Fix: match_path_segments now tries each split point and recurses on the
remaining template. Templates with ** mid-pattern skip trie insertion
and fall back to the corrected linear matcher.

🤖 Generated with Claude Code

I3eg1nner and others added 3 commits August 18, 2026 15:35
The ** glob was greedy — it consumed all remaining path segments and
never checked what followed in the template. A route like /admin/**/settings
would match /admin/anything, bypassing the /settings guard.

Two fixes:
- match_path_segments: try each split point for ** and recurse on the
  remaining template. First match wins.
- DynamicRouteTrieNode: the trie can't represent ** followed by more
  segments (insert stores DeepWildcard and returns, discarding the
  tail). Skip trie insertion for these templates and fall back to the
  linear matcher, which now handles them correctly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Two issues fixed:

1. When the path is exhausted and the current template part is **,
   match_path_segments returned Some immediately without checking if
   more template parts follow. /admin/**/settings matched /admin.
   Fix: recurse past ** to validate the remaining template.

2. find_route returned the first trie hit without checking whether a
   lower-order route existed only in the linear list (because **
   mid-pattern templates skip trie insertion). This broke registration
   order. Fix: within each method group, compare trie and linear
   results by order and take the lowest.

Added regression tests for both cases.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Verifies that /admin/**/settings registered before /admin/:id/settings
wins when matching /admin/x/settings (params should contain "_", not "id").

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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