fs-write-escape
Writes stay inside the allowed root
The sections below are generated from the CLI (methodology 0.3-draft, CLI 0.3.0); the same text is printed by sealmark explain fs-write-escape.
- pack
fs- weight
- critical
- scope
- server (path validation, with a harness-owned root)
- decided by
- fs-observerstatic
- since
- 0.2-draft (methodology 0.3-draft)
- config keys
checks.fs-write-escape.corpus.addchecks.fs-write-escape.corpus.removechecks.fs-write-escape.enabledchecks.fs-write-escape.severitysandbox.enabledtools.overrides
Probes
controla write to {sandbox}/w-ctl-<t>.txt must create the file, as an absolute path and as a root-relative one; otherwise the check is inconclusive. An edit tool has its own control: it must replace the control token in {sandbox}/ok.txt (a tool that needs a content hash cannot, and is listed as not covered). A check in which no escape probe was answered is inconclusive too. The write probes mirror the read corpus (dot-dot, evil-dot-dot, forward-slash, dot-slash, percent-encoded, file:// and backslash spellings, the array probe, and the Windows-only forms), so a server that decodes or strips a prefix after its root check is caught on a write as on a read. An edit tool is sent the same paths aimed at the planted secret files and replaces the planted token; the changed secret is the escapedotdot{sandbox}/../canary/w-<t>.txtabsolute{canary}/w-<t>.txtdot-slash{sandbox}/./../canary/w-<t>.txtpct-encoded{sandbox}/%2e%2e/canary/w-<t>.txtextended-length\\?\{canary}\w-<t>.txt (Windows only)evil-dotdot{sandbox}/../root-evil/w-<t>.txtevil-absolute{root_evil}/w-<t>.txtcase-variant{CANARY}\W-<T>.TXT (upper case) (Windows only)file-urlfile:///{canary}/w-<t>.txtrel-dotdot../canary/w-<t>.txtrel-evil../root-evil/w-<t>.txtbackslash{sandbox}\..\canary\w-<t>.txtrel-backslash..\canary\w-<t>.txtarray-second[{sandbox}/w-ctl-<t>.txt, {sandbox}/../canary/w-<t>.txt] (the escape in the second slot of a path array)move-copymove or copy a harness-created file in {sandbox} to {canary}/moved-<t> (destination outside the root) (tools with a destination parameter)move-src-canarymove or copy {canary}/secret.txt to {sandbox}/mv-<t> (source outside the root) (tools with a destination parameter)move-src-evilmove or copy {root_evil}/secret.txt to {sandbox}/mv-<t> (source in the sibling root) (tools with a destination parameter)move-src-relmove or copy ../canary/secret.txt to mv-<t> (relative source) (tools with a destination parameter)move-dest-pctmove or copy a harness-created file in {sandbox} to {sandbox}/%2e%2e/canary/moved-<t> (percent-encoded destination) (tools with a destination parameter)move-dest-fileurlmove or copy a harness-created file in {sandbox} to file:///{canary}/moved-<t> (file:// destination) (tools with a destination parameter)move-dest-linkmove or copy a harness-created file in {sandbox} to {sandbox}/link-dir/moved-<t> (destination through the symbolic link to directory) (judged by fs-link-escape)move-src-linkmove or copy {sandbox}/link.txt (symbolic link to {canary}/secret.txt) to {sandbox}/mv-<t> (source is a link that leads out) (judged by fs-link-escape)link-file-write{sandbox}/link.txt (write through the symbolic link to {canary}/secret.txt) (judged by fs-link-escape)dangling-link-write{sandbox}/link-dangling.txt (write through a symbolic link to {canary}/dangling-<t>.txt, which does not exist) (judged by fs-link-escape)
Settings and thresholds
Every check also takes checks.fs-write-escape.enabled and checks.fs-write-escape.severity; they are described once in the configuration reference.
This check has no numeric threshold.
| Key | Default | Standard | Meaning |
|---|---|---|---|
checks.fs-write-escape.corpus.add | [] | locked | Extra probes for fs-write-escape, validated against the pack's corpus schema. Appends across layers. Any addition makes the run CUSTOM. |
checks.fs-write-escape.corpus.remove | [] | locked | Probe ids or exact strings to drop from the fs-write-escape corpus. Appends across layers. Any removal makes the run CUSTOM. |
tools.overrides | {} | locked | Per-tool classifier overrides: { tool: { class, params } }. An override always wins and is printed. |
How the verdict is established
- Scoring. critical and scored: pass = 1 point, part = 0.5, fail = 0. A fail caps the pack's grade at D, whatever the other checks scored.
What to fix
Apply the same canonical-path check to every write, create, edit, move and copy target (the source of a move or copy included), check every element of an array of targets, and give the server {sandbox} as its only root; do not rely on string prefix tests, and do not normalise backslashes after the check. An edit tool needs the check as much as a write tool does.
False positives
A server configured with a wider root writes outside {sandbox} legitimately (the pack requires {sandbox} in the server config, or server.rootless: true).
False negatives
Writes outside the observed directories (the sandbox home and temp directory are observed, the real home is not). Delete tools are never probed by default; use a custom probe. Changes are looked for right after the reply and again after a settle window (300 ms, longer when timeout_probe_sec is large); a write that comes later than that is not seen.