fix(utils): fix sibling-directory escape in materializeFiles path check - #603
Open
herdiyana256 wants to merge 1 commit into
Open
fix(utils): fix sibling-directory escape in materializeFiles path check#603herdiyana256 wants to merge 1 commit into
herdiyana256 wants to merge 1 commit into
Conversation
materializeFiles guarded against escaping its target directory with
`fullPath.startsWith(resolvedBaseDir)`, a path-separator-unaware prefix match:
a relative name like `../<dir>-evil/x` resolves outside the target directory
but still starts with the same string, so it passed the check. Since the
resulting directories are created with `fs.mkdir(..., {recursive: true})`, this
let a caller-supplied file name write outside the intended directory as long as
its resolved sibling path happened to share the base directory's name as a
prefix.
materializeFiles is reachable from run_skill_script_tool /
run_skill_inline_script_tool with output files from a configured
CodeExecutor, including AgentEngineSandboxCodeExecutor, which decodes the
file name from the remote sandbox's own execution-result metadata; a caller
with no other privileges beyond choosing that file name could reach a
directory outside the one materializeFiles was scoped to.
Require a path-separator boundary (or exact equality) instead of a bare
prefix match, matching the containment check already used in
FileArtifactService's assertInsideRoot. Add a regression test for the specific
gap: an escape into a sibling directory that shares a name prefix with the
target directory, which the existing `../escape.txt`-style test does not
exercise (mkdtemp's random suffix means that case never collides with a real
sibling name).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
materializeFiles (core/src/utils/file_utils.ts) guards its target directory with
fullPath.startsWith(resolvedBaseDir)— a path-separator-unaware prefix match. A relative file name like../<dir>-evil/xresolves to a sibling of the target directory but still satisfies that check, sinceresolvedBaseDirand the sibling path share the same string prefix with no separator required between them. Because the resulting directory is created withfs.mkdir(path.dirname(finalPath), {recursive: true}), the sibling directory does not need to already exist.materializeFilesis called with nodirargument (defaulting toprocess.cwd()) fromrun_skill_script_tool.tsandrun_skill_inline_script_tool.tsonresult.outputFiles, which come back from whateverCodeExecutoris configured — includingAgentEngineSandboxCodeExecutor, which decodes each output file's name directly from the remote sandbox execution result's metadata (attributes['file_name'], base64-decoded, unvalidated). So a file name chosen by code running inside that isolated sandbox can, via this gap, land outside the directorymaterializeFileswas scoped to on the orchestrator host.Confirmed by executing the real function: with target dir
/tmp/x/sandboxdir, an output file named../sandboxdir-pwned/shell.jswas written to/tmp/x/sandboxdir-pwned/shell.js, outside the intended directory.This replaces the check with a helper requiring a path-separator boundary (or exact equality) — the same containment pattern already used by
FileArtifactService.assertInsideRoot(added in #210 for a related but distinct traversal in that file). Adds a regression test for exactly this gap: the existing../escape.txt-style test usesfs.mkdtemp's randomly-suffixed directory name, so it never happens to collide with a real sibling name and does not exercise this path.