You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Split out of #480 / #481 per review feedback on #481: grouping the security-sensitive findings from the multi-agent codebase audit separately from the UX/robustness ones so each can be reviewed and landed independently.
This covers 3 of the 9 original findings, plus the securefile/oauth Windows lock-contention pair (not explicitly named in the split request, but grouped here since securefile.go backs credstore's encrypted API-key storage and the fix mirrors an existing oauth/encrypt.go fix one-for-one):
Sandbox deny-grants are case-sensitive on Windows — internal/sandbox/grant_scope.go. Persistent per-path grants (ScopeFile/ScopeDir) compared paths with plain ==/HasPrefix, unlike the workspace-boundary check which uses case-insensitive filepath.Rel. A user-authored deny --path C:\Users\me\project\Secrets silently failed to match a request spelled c:\users\me\project\secrets — same file on a case-insensitive filesystem, but the deny didn't apply.
Windows lock-contention fix applied inconsistently — internal/securefile/securefile.go had the pre-fix(oauth): retry secret-lock on Windows ERROR_ACCESS_DENIED (delete-pending race) #445 bug that internal/oauth/encrypt.go already fixed: it only treated os.ErrExist as lock contention, not ERROR_ACCESS_DENIED. Since securefile.go backs credstore's encrypted API-key storage, concurrent zero processes on Windows could spuriously hard-fail with "Access is denied". Both files also discarded the real lock-creation error in favor of a subsequent unrelated ErrNotExist, masking genuine ACL failures behind a misleading "timed out: file does not exist".
Update checksum didn't cross-check the archive filename — internal/update/apply.go. VerifySHA256Checksum hashes whichever file the checksum text names, not necessarily the archive that was downloaded; a checksum file naming a different (but validly-hashed) file could vouch for the wrong bytes before extraction.
extractZip didn't reject symlink-mode entries — internal/update/extract.go, unlike extractTarGz which already rejects non-regular tar entries.
Fix
PR: (to be linked)
All four fixes ship with regression tests. go build ./... and go test ./internal/sandbox/... ./internal/securefile/... ./internal/oauth/... ./internal/update/... pass.
Scope note
Originally reported and fixed together in #481, which is being split into smaller, independently-reviewable PRs per maintainer request.
Summary
Split out of #480 / #481 per review feedback on #481: grouping the security-sensitive findings from the multi-agent codebase audit separately from the UX/robustness ones so each can be reviewed and landed independently.
This covers 3 of the 9 original findings, plus the securefile/oauth Windows lock-contention pair (not explicitly named in the split request, but grouped here since securefile.go backs credstore's encrypted API-key storage and the fix mirrors an existing oauth/encrypt.go fix one-for-one):
internal/sandbox/grant_scope.go. Persistent per-path grants (ScopeFile/ScopeDir) compared paths with plain==/HasPrefix, unlike the workspace-boundary check which uses case-insensitivefilepath.Rel. A user-authoreddeny --path C:\Users\me\project\Secretssilently failed to match a request spelledc:\users\me\project\secrets— same file on a case-insensitive filesystem, but the deny didn't apply.internal/securefile/securefile.gohad the pre-fix(oauth): retry secret-lock on Windows ERROR_ACCESS_DENIED (delete-pending race) #445 bug thatinternal/oauth/encrypt.goalready fixed: it only treatedos.ErrExistas lock contention, notERROR_ACCESS_DENIED. Sincesecurefile.gobackscredstore's encrypted API-key storage, concurrentzeroprocesses on Windows could spuriously hard-fail with "Access is denied". Both files also discarded the real lock-creation error in favor of a subsequent unrelatedErrNotExist, masking genuine ACL failures behind a misleading "timed out: file does not exist".internal/update/apply.go.VerifySHA256Checksumhashes whichever file the checksum text names, not necessarily the archive that was downloaded; a checksum file naming a different (but validly-hashed) file could vouch for the wrong bytes before extraction.extractZipdidn't reject symlink-mode entries —internal/update/extract.go, unlikeextractTarGzwhich already rejects non-regular tar entries.Fix
PR: (to be linked)
All four fixes ship with regression tests.
go build ./...andgo test ./internal/sandbox/... ./internal/securefile/... ./internal/oauth/... ./internal/update/...pass.Scope note
Originally reported and fixed together in #481, which is being split into smaller, independently-reviewable PRs per maintainer request.