s3: fix wildcard matcher skipping '*' targets in policy patterns (#12034)

* s3: check pattern '*' before literal equality in matchWildcardString

When the target string carried a '*' at the offset of the pattern's '*',
the literal-equality case consumed it as a one-character match and no
backtrack point was recorded, so the comparison returned false. A Deny
Resource carrying a policy variable, or an Allow carrying NotResource,
could then be sidestepped by an object key containing '*' at the aligned
offset.

* test: cover literal asterisks in wildcard match targets

---------

Co-authored-by: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
Chris LuandDevin authored and GitHub committed 2026-10-24 08:20:22 -07:00
1 parent 1d2d9dfed2
commit 4c2c0ff21c
2 files changed
+11 -3

No files matched your search

+5 -3
View File
@@ -155,13 +155,15 @@ func matchWildcardString(pattern, str string) bool {
for targetIndex < len(str) {
switch {
case patternIndex < len(pattern) && (pattern[patternIndex] == '?' || pattern[patternIndex] == str[targetIndex]):
targetIndex++
patternIndex++
// '*' must be checked before literal equality so a '*' in the target
// cannot consume the pattern wildcard without a backtrack point
case patternIndex < len(pattern) && pattern[patternIndex] == '*':
lastStarIndex = patternIndex
lastStarMatchIndex = targetIndex
patternIndex++
case patternIndex < len(pattern) && (pattern[patternIndex] == '?' || pattern[patternIndex] == str[targetIndex]):
targetIndex++
patternIndex++
case lastStarIndex != -1:
patternIndex = lastStarIndex + 1
lastStarMatchIndex++
@@ -27,6 +27,12 @@ func TestMatchesWildcard(t *testing.T) {
{"Pattern with regex special chars", "test[abc]", "test[abc]", true},
{"Pattern with dots", "test.txt", "test.txt", true},
{"Pattern with dots and wildcard", "*.txt", "test.txt", true},
{"Star in target at pattern star offset", "a/*", "a/*b", true},
{"Star in target equals pattern", "a/*", "a/*", true},
{"Star in target past pattern star offset", "a/*", "a/x*y", true},
{"Question mark matches literal star", "a/?c", "a/*c", true},
{"Star in target is not a wildcard", "ab*", "a*b", false},
{"ARN pattern with star in key", "arn:aws:s3:::bucket/finance/*", "arn:aws:s3:::bucket/finance/*star.txt", true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {