Commit bb32f4b
committed
fix(security): reject writes through symlinked parent dirs in sandbox
ToolExecutor::validate_path correctly canonicalized requests when the
target file already existed, but the non-existent-path branch only ran
normalize_relative on the requested path components and then joined
them onto the canonicalized sandbox without resolving symlinks. An
agent able to create a file inside the sandbox could plant a symlink
to anywhere on disk and then write through it:
run_command ln -s /etc evil
write_file { path: "evil/passwd", content: ... }
The leaf "evil/passwd" did not exist, so canonicalization was skipped
and tokio::fs::write followed the symlink, writing arbitrary content
outside the sandbox.
The fix walks up the candidate path to the deepest existing ancestor,
canonicalizes that ancestor (which resolves any symlink in the chain),
and rejects the request if the resolved ancestor falls outside the
sandbox. The leaf path is still returned as-is so write_file's
create_dir_all behaviour is preserved.
A regression test plants a symlink and attempts the write — it now
fails with a sandbox-escape error.1 parent 8ff8d61 commit bb32f4b
1 file changed
Lines changed: 66 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
127 | 127 | | |
128 | 128 | | |
129 | 129 | | |
130 | | - | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
131 | 155 | | |
132 | 156 | | |
133 | 157 | | |
| |||
435 | 459 | | |
436 | 460 | | |
437 | 461 | | |
| 462 | + | |
| 463 | + | |
| 464 | + | |
| 465 | + | |
| 466 | + | |
| 467 | + | |
| 468 | + | |
| 469 | + | |
| 470 | + | |
| 471 | + | |
| 472 | + | |
| 473 | + | |
| 474 | + | |
| 475 | + | |
| 476 | + | |
| 477 | + | |
| 478 | + | |
| 479 | + | |
| 480 | + | |
| 481 | + | |
| 482 | + | |
| 483 | + | |
| 484 | + | |
| 485 | + | |
| 486 | + | |
| 487 | + | |
| 488 | + | |
| 489 | + | |
| 490 | + | |
| 491 | + | |
| 492 | + | |
| 493 | + | |
| 494 | + | |
| 495 | + | |
| 496 | + | |
| 497 | + | |
| 498 | + | |
| 499 | + | |
| 500 | + | |
| 501 | + | |
| 502 | + | |
438 | 503 | | |
439 | 504 | | |
440 | 505 | | |
| |||
0 commit comments