Validate manifest paths on read, not only on write (path traversal in Checker) #61
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Context
ValidatePath()(mfer/builder.go:35-66) enforces the path invariants —valid UTF-8, no backslashes, no leading
/, no..or empty segments — andis called from
Builder.AddFile(mfer/builder.go:142) andBuilder.AddFileWithHash(mfer/builder.go:232).That is write-side only. Paths arriving from an untrusted
.mffile arenever validated:
NewManifestFromReader/deserializeInner()inmfer/deserialize.godonot validate any entry path.
mfer/checker.go:315doesabsPath := filepath.Join(string(c.basePath), entry.GetPath())on the rawmanifest path with no validation and no sanitization at all.
So a hostile
index.mfcontaining../../etc/passwdcausesmfer checktostat and read outside
basePath.internal/cli/fetch.gohas its ownseparate
sanitizePath()and is not affected; the libraryCheckeris.Severity is limited for
checktoday because the operation is read-only andreports a mismatch rather than writing anything — but this is a library
consumed by other programs, the invariants are already specified, and the
enforcement gap is exactly the kind of thing that becomes a write primitive
the first time someone adds a restore or extract path.
Definition of done
manifest benefits rather than each call site re-implementing the check.
A manifest containing an entry that fails
ValidatePathis rejected witha wrapped sentinel error naming the offending path.
mfer/checker.gonever joins an unvalidated manifest path ontoc.basePath.../escape,a/../../escape, an absolute path, a backslash path, anempty path, and invalid UTF-8, and asserts each is rejected at load time
with an error identifying the path. Plus a test asserting a valid manifest
still round-trips unchanged.
make checkpasses.TODO.mdupdated in the same commit.Implementation requirements
Checker— thegap is that untrusted input enters the library unvalidated, and every
future consumer would have to remember the check.
ValidatePathrather than writing a second, subtlydifferent validator. If
ValidatePathis missing a rule needed here(e.g. rejecting absolute Windows-style paths), extend
ValidatePathandcover the new rule with a test.
%w, consistent with theexisting error style in the package.
the format is invalid and must fail loudly. Silently ignoring bad entries
would let an attacker hide files from a
check.(closes #61).