Summary
A sandbox LocalDir source can be validated as a local directory and then swapped to a symlink before/open-during copy. On current main, the copy can follow the swapped target and write files from that target into the sandbox workspace.
Reproduced on current main
Checked against openai/openai-agents-python@65774ce8.
LocalDir(src=Path("src")) source-root swap: NO_RAISE, wrote /workspace/copied/secret.txt.
LocalDir(src=Path(".")) base-dir/root-open swap: NO_RAISE, wrote /workspace/copied/secret.txt.
Expected
After validation, local directory materialization should reject source path identity changes and symlink swaps before any sandbox writes occur.
Candidate fix
PR #3408 adds pre-open no-follow stat checks and post-open identity comparisons for the initial source root, path components, nested directories, and file leaves. It also adds regressions that simulate no-follow not preventing the swap.
PR branch check
Checked fallintoplace:fix/local-dir-symlink-swap at 97b5c193.
LocalDir(src=Path("src")) swap: raised LocalDirReadError with reason=path_changed_during_copy, child=src.
LocalDir(src=Path(".")) swap: raised LocalDirReadError with reason=path_changed_during_copy, child=..
Related PR: #3408
Summary
A sandbox
LocalDirsource can be validated as a local directory and then swapped to a symlink before/open-during copy. On currentmain, the copy can follow the swapped target and write files from that target into the sandbox workspace.Reproduced on current main
Checked against
openai/openai-agents-python@65774ce8.LocalDir(src=Path("src"))source-root swap:NO_RAISE, wrote/workspace/copied/secret.txt.LocalDir(src=Path("."))base-dir/root-open swap:NO_RAISE, wrote/workspace/copied/secret.txt.Expected
After validation, local directory materialization should reject source path identity changes and symlink swaps before any sandbox writes occur.
Candidate fix
PR #3408 adds pre-open no-follow stat checks and post-open identity comparisons for the initial source root, path components, nested directories, and file leaves. It also adds regressions that simulate no-follow not preventing the swap.
PR branch check
Checked
fallintoplace:fix/local-dir-symlink-swapat97b5c193.LocalDir(src=Path("src"))swap: raisedLocalDirReadErrorwithreason=path_changed_during_copy,child=src.LocalDir(src=Path("."))swap: raisedLocalDirReadErrorwithreason=path_changed_during_copy,child=..Related PR: #3408