fs-read-escape

Reads stay inside the allowed root

shipped

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-read-escape.

pack
fs
weight
critical
scope
server (path validation, with a harness-owned root)
decided by
responsestatic
since
0.2-draft (methodology 0.3-draft)
config keys
checks.fs-read-escape.corpus.addchecks.fs-read-escape.corpus.removechecks.fs-read-escape.enabledchecks.fs-read-escape.severitysandbox.enabledtools.overrides

Probes

  • control {sandbox}/ok.txt must be readable first, as an absolute path and as a root-relative one (base64 in the reply is decoded, and so are resource, image and audio blocks); otherwise the check is inconclusive, and so it is when a tool that reads files exists but cannot be called (a required parameter the harness cannot fill). A search or listing tool is asked with a pattern that matches both ok.txt and secret.txt: none, txt, *txt*, *, *.txt, the first that lists ok.txt. The root-relative probes run for every tool whose root-relative control worked, and the array probe for a tool with an array path parameter. A high-confidence read tool whose control failed makes the check a part, never a pass. A check in which no escape probe was answered (every call timed out, could not be built or was removed by config) is inconclusive, never a pass
  • dotdot {sandbox}/../canary/secret.txt
  • absolute {canary}/secret.txt
  • dot-slash {sandbox}/./../canary/secret.txt
  • pct-encoded {sandbox}/%2e%2e/canary/secret.txt
  • extended-length \\?\{canary}\secret.txt (Windows only)
  • evil-dotdot {sandbox}/../root-evil/secret.txt
  • evil-absolute {root_evil}/secret.txt
  • case-variant {CANARY}\SECRET.TXT (upper case) (Windows only)
  • file-url file:///{canary}/secret.txt
  • rel-dotdot ../canary/secret.txt
  • rel-evil ../root-evil/secret.txt
  • backslash {sandbox}\..\canary\secret.txt
  • rel-backslash ..\canary\secret.txt
  • array-second [{sandbox}/ok.txt, {sandbox}/../canary/secret.txt] (the escape in the second slot of a path array)

Settings and thresholds

Every check also takes checks.fs-read-escape.enabled and checks.fs-read-escape.severity; they are described once in the configuration reference.

This check has no numeric threshold.

KeyDefaultStandardMeaning
checks.fs-read-escape.corpus.add[]lockedExtra probes for fs-read-escape, validated against the pack's corpus schema. Appends across layers. Any addition makes the run CUSTOM.
checks.fs-read-escape.corpus.remove[]lockedProbe ids or exact strings to drop from the fs-read-escape corpus. Appends across layers. Any removal makes the run CUSTOM.
tools.overrides{}lockedPer-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

Resolve every requested path to an absolute canonical path and check that it is inside the allowed root before reading; reject .., absolute paths, encoded variants and drive or device forms, and check every element of an array of paths, not only the first. On POSIX a backslash is an ordinary file-name character: do not turn it into a separator after the root check. A server that takes no root argument has its working directory as its root: say so with server.rootless: true.

False positives

A server deliberately configured to allow more than {sandbox} (a whole drive, the home directory) reads the canary legitimately; the pack requires {sandbox} in the server config (or server.rootless: true, for a server that works in its working directory) and is not applicable otherwise.

False negatives

Encodings and path forms outside the corpus (8.3 short names, device paths, unicode normalisation); tools the classifier did not treat as file tools. List tools count only when the listing shows secret.txt.