fix: confine Cache file lookups to the configured directories (SLT-18)#74
Conversation
Cache.readFile joined a script-controlled name to each configured dir with no post-join check. filepath.Join cleans embedded ".." segments, so a name like "../secret.star" — supplied to Run or, more importantly, chosen by an untrusted script via load() — resolved above the configured directory and read (and executed) a sibling or parent .star file. Add a containment check (withinDir): a candidate that escapes a dir via ".." is skipped. A name that stays within a different configured dir is still served from that one; only a name that escapes every configured dir falls through to not-found. In-tree and subdirectory access are unaffected. Confinement is not a promised guarantee of New() (real sandboxing is the host layer's job), so this is defense in depth, not a fix to a stated invariant — but the directory search should not silently reach outside the directories it was given. Test-first: TestCachePathContainment (Run + load() escape both rejected, in-tree/subdir access preserved) and TestCacheMultiDirSiblingAccess. Backlog: SLT-18. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Up to standards ✅🟢 Issues
|
| Metric | Results |
|---|---|
| Complexity | 22 |
| Duplication | 0 |
🟢 Coverage 89.47% diff coverage · +0.31% coverage variation
Metric Results Coverage variation ✅ +0.31% coverage variation (-1.00%) Diff coverage ✅ 89.47% diff coverage Coverage variation details
Coverable lines Covered lines Coverage Common ancestor commit (bde646d) 2139 1932 90.32% Head commit (8198ead) 2157 (+18) 1955 (+23) 90.64% (+0.31%) Coverage variation is the difference between the coverage for the head and common ancestor commits of the pull request branch:
<coverage of head commit> - <coverage of common ancestor commit>Diff coverage details
Coverable lines Covered lines Diff coverage Pull request (#74) 19 17 89.47% Diff coverage is the percentage of lines that are covered by tests out of the coverable lines that the pull request added or modified:
<covered lines added or modified>/<coverable lines added or modified> * 100%
NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #74 +/- ##
==========================================
+ Coverage 87.32% 87.67% +0.35%
==========================================
Files 8 8
Lines 1672 1680 +8
==========================================
+ Hits 1460 1473 +13
+ Misses 130 127 -3
+ Partials 82 80 -2 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
What
Cache.readFilejoined a script-controlled name to each configured directory with no post-join containment check.filepath.Joincleans embedded..segments, so a name like../secret.starresolved above the configured directory and was read and executed. Both entry points reach this function:Cache.Runand, more importantly,load()— whose module strings are fully script-controlled, so an untrusted script could read any.star-parseable file the host process can reach.(The absolute-path vector does not apply —
filepath.Joinneutralizes a leading/; only..traversal escapes.)Fix
withinDirrejects a candidate that climbs out of a directory via... A name that escapes one configured dir but lands inside another configured dir is still served from that one; only a name escaping every dir falls through to not-found. In-tree and subdirectory access are unchanged.Confinement is not a promised guarantee of
New()(real sandboxing belongs to the host layer), so this is defense in depth rather than a fix to a stated invariant — but the directory search should not silently reach outside the directories it was given.Test-first
TestCachePathContainment(Run +load()escape both rejected; in-tree + subdir access preserved) andTestCacheMultiDirSiblingAccess(the escape-one-dir-but-within-another case) fail before the fix.Verification
go test -race -count=2 ./...,go vet,gofmt -lclean, Dockergolang:1.19race run green.Backlog: SLT-18