Skip to content

acl: support single-label wildcards in domain globs - #344

Merged
shubh-stripe merged 3 commits into
masterfrom
shubh/acl-label-wildcards
Oct 6, 2026
Merged

shubh-stripe merged 3 commits into
masterfrom
shubh/acl-label-wildcards

Conversation

@shubh-stripe

@shubh-stripe shubh-stripe commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

Domain globs only supported a leading *., so patterns like access-analyzer.*.amazonaws.com (#241) had to be listed host by host. This PR allows one wildcard confined to a single label:

  • access-analyzer.*.amazonaws.com matches exactly one label.
  • api*.example.com and web*-canary.example.com match one or more characters within a label, never a ..

Validation rejects multiple wildcards, wildcards in the TLD, and wildcards directly under a public suffix (e.g. foo*.github.io, login.*.com).

A wildcard also can't match a host owned by someone else, according to the public suffix list. For example, access-analyzer.*.amazonaws.com doesn't match access-analyzer.s3.amazonaws.com, an S3 bucket anyone can create. When that's the only reason a request is denied or reported, the deny message says so:

rule has enforce policy; wildcard 'sts.*.amazonaws.com' was not applied because 'us-east-1.amazonaws.com' is on the public suffix list

An ACL can turn the check off with unsafe_allow_wildcards_across_public_suffixes: true. The global deny list always skips it on purpose. There, matching too much only blocks extra hosts, while matching too little would let denied traffic through.

Existing globs validate and match exactly as before. Error messages for globs with non-leading wildcards have changed.

Limitations

  • Some hosts sit under, or are themselves, public suffixes, e.g. all of us-east-1.amazonaws.com and s3.<region>.amazonaws.com. Without the opt-out, these never match and need explicit entries.
  • The hint adds new decision_reason values, so anything grouping logs by that field sees them.
  • Matching depends on the public suffix list version compiled in via x/net.
  • A label wildcard doesn't match the bare prefix or subdomains: api*.example.com doesn't match api.example.com.

Testing

Run locally, not committed:

  • A differential test against the previous implementation on ~4,000 real-world ACL entries.
  • Fuzzing against a reference model, and of the hint and opt-out: ~115M executions.
  • End-to-end CONNECT and HTTP requests through a running proxy, including case, trailing-dot, Unicode and malformed-host variants, and the deny message clients receive.
  • Benchmarks: no regression in Decide.

🤖 Generated with Claude Code

shubh-stripe and others added 2 commits October 6, 2026 14:57
Domain globs only allowed a leading "*.", so patterns like access-analyzer.*.amazonaws.com (#241) or api*.example.com had to be expanded by hand, and new regions or hosts silently fell outside the list. Globs may now also contain a single wildcard that is confined to one label: either a whole non-leftmost label or a suffix after a literal prefix. Such a wildcard never crosses a dot, must be followed by a registrable domain, and is rejected in the TLD, Punycode labels, IP-shaped patterns, and directly after a leading "*" since that is usually a typo for "*.".

Outside the global deny list, a host only matches if its registrable domain per the public suffix list equals that of the glob's literal suffix. Without this, access-analyzer.*.amazonaws.com would allow access-analyzer.s3.amazonaws.com, an S3 bucket anyone can claim. The cost is that hosts the PSL splits off, like the us-east-1.amazonaws.com suffix, must be listed explicitly. The global deny list skips the check so a denied glob blocks every host it reads as.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Committed-By-Agent: claude
The matcher re-derived a label wildcard's structure on its own and only rejected some of the shapes that validation rejects, so an unvalidated glob such as 1*.0.0.1 still matched an IP address in the global deny list. Validation and matching now share one parser, and a glob only matches after passing the same checks as ValidateDomainGlob. The normalization and public suffix checks run only after the labels match, so a miss costs no more than before.

The README now also notes that hosts that are public suffixes themselves, such as regional S3 endpoints, never match a wildcard, and that denying a label wildcard covers neither the bare prefix nor subdomains.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Committed-By-Agent: claude
@shubh-stripe

Copy link
Copy Markdown
Contributor Author

r? @gauthamw-stripe

A label wildcard that lands on a public suffix, such as sts.*.amazonaws.com against sts.us-east-1.amazonaws.com, is skipped in allow lists. Until now the resulting denial read like a missing entry, so the decision reason now names the skipped wildcard and the public suffix responsible. The hint is only computed on denied or reported requests, and Reason is not a metric tag.

Some ACLs may prefer the broader match, so unsafe_allow_wildcards_across_public_suffixes turns the check off for every allow list in that ACL. It stays off by default, validation is unchanged, and HostMatchesGlob and the IP filter bypass list remain strict because they don't belong to an ACL.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Committed-By-Agent: claude
@shubh-stripe
shubh-stripe merged commit ac3ca09 into master Oct 6, 2026
21 checks passed
@shubh-stripe
shubh-stripe deleted the shubh/acl-label-wildcards branch October 6, 2026 12:20
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.

2 participants