Skip to content

fix(permissions): match glob wildcards across path separators#3605

Open
parveshsaini wants to merge 1 commit into
docker:mainfrom
parveshsaini:parveshsaini/fix/permission-deny-glob-separator
Open

fix(permissions): match glob wildcards across path separators#3605
parveshsaini wants to merge 1 commit into
docker:mainfrom
parveshsaini:parveshsaini/fix/permission-deny-glob-separator

Conversation

@parveshsaini

Copy link
Copy Markdown

Closes #3604

What

matchGlob in pkg/permissions falls back to filepath.Match for any pattern that isn't a plain trailing
wildcard. filepath.Match's * and ? match only non-separator characters, so they stop at / (and at
\ on Windows). This translates the glob to an anchored regexp whose */? span any character instead.

Why

Permission patterns match argument values — shell commands, file paths, URLs — which routinely contain /.
Because of the separator boundary, a rule with a non-trailing wildcard silently fails to match once the
value contains a /:

permissions:
  deny:
    - "shell:cmd=*rm -rf*"
  • shell with cmd = "rm -rf tmp" → denied ✅
  • shell with cmd = "rm -rf /"not denied (falls through to Ask) ❌

For a deny rule this is the unsafe direction — it fails open. In an interactive session the fall-through
to Ask still prompts, so the practical exposure is a degraded control; it becomes a real bypass under
--yolo, non-interactive / auto-approval runs, or when an overlapping allow rule is present. The same
boundary also silently breaks allow rules, though those fail closed.

The existing docstring already stated the intent — "for argument matching we want * to match any characters
including spaces"
— but that only held for the trailing-wildcard fast path (sudo*), which is why casual
testing with trailing-only patterns never surfaced this.

How

  • Replace the filepath.Match fallback in matchGlob with globToRegexp + regexp.MatchString.
  • globToRegexp translates a filepath.Match-style glob into an anchored regexp: *.*, ?.,
    character classes ([...]) copied through (bracket syntax is shared with regexp), everything else matched
    literally via regexp.QuoteMeta.
  • The trailing-* prefix-match fast path and the case-insensitive lowercasing are unchanged.
  • No new dependencies (regexp is stdlib; path/filepath import dropped).

This keeps all existing matchGlob semantics (*, ?, [...], case-insensitivity) — only the separator
boundary changes.

Tests

  • New TestDenyGlobCrossesPathSeparator: end-to-end via CheckWithArgs, asserting a *rm -rf* deny rule
    blocks both rm -rf tmp and rm -rf /.
  • Extended the TestMatchGlob table with separator-crossing cases (*rm -rf*, */etc/*, a?c vs a/c).

These fail on main and pass with the fix. Full pkg/permissions suite, go vet, gofmt, and
golangci-lint are all green (Go 1.26.4).

--- PASS: TestDenyGlobCrossesPathSeparator (0.00s)
--- PASS: TestMatchGlob (0.00s)
ok  	github.com/docker/docker-agent/pkg/permissions

Signed-off-by: parveshsaini <parveshsaini619@gmail.com>
@parveshsaini parveshsaini requested a review from a team as a code owner July 11, 2026 15:03
@aheritier aheritier added area/security Authentication, authorization, secrets, vulnerabilities kind/fix PR fixes a bug (maps to fix:). Use on PRs only. labels Jul 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/security Authentication, authorization, secrets, vulnerabilities kind/fix PR fixes a bug (maps to fix:). Use on PRs only.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Permission deny rules fail open for argument values containing / (matchGlob uses filepath.Match)

2 participants