Files
Andrey Kumanyaev e391f406e1 Refuse symlinks that escape the repository when serving artifacts
The artifacts pipeline carried the same weakness as the indexer walk, found
while auditing for other instances of it. An `artifacts:` manifest entry
resolves against the repository, but all three expansion branches reach the
filesystem in a way that follows links — os.Stat for a literal path,
filepath.Glob for a single-segment pattern, filepath.WalkDir for a recursive
one. A link such as `docs/schema.sql -> /etc/shadow` therefore satisfied a
manifest entry, and get_artifact returned its bytes verbatim: that handler
read the file after resolveFilePath, which blocks lexical `../` traversal
but happily follows a symlink, and it was the one content-serving handler
that never applied the confinement check the others do.

Glob expansion now refuses an escaping link in each branch, the read in
materializeOne re-checks so an artifact list from a persisted index cannot
reintroduce it, and get_artifact applies the same guard as every other tool
that puts file content into a response.
2026-08-05 00:08:10 +02:00
..