FileJail
Defined in: packages/tools/src/file/jail.ts:81
Confines file access to configured allow/deny path bounds. Every requested path is
resolved and checked (after symlink resolution) against those bounds. Defends against
.. traversal and a symlink planted inside an allow root pointing outside it (or into
a deny path).
Known limitation (TOCTOU): this is a check-then-use pattern, not a kernel-enforced
boundary — there’s a window between a resolve* call’s realpath check and the caller’s
actual readFile/writeFile on that same path where a concurrent filesystem change (e.g.
something swaps a symlink into place) could in principle slip through. A fully closed
version would operate on a file descriptor (open → fstat/read) instead of a path, so
there’s no gap between check and use; this package doesn’t do that yet. Matches the threat
model this jail is scoped to (the model is the adversary, via tool-call arguments — not a
concurrent local filesystem race) but is worth knowing if that threat model ever changes.
A subprocess-level, kernel-enforced sandbox (e.g. Landlock, sandbox-exec) doesn’t have
this gap; this jail does.
Platform support: tested on Linux and macOS only. Windows is untested and not
currently supported — path.isAbsolute/path.relative/path.sep behave differently
there (drive letters, UNC paths, case-insensitive-but-case-preserving filesystems), and
none of that has been verified.
Properties
Section titled “Properties”
readonlycwd:string
Defined in: packages/tools/src/file/jail.ts:83
Relative-path base, resolved absolute (not yet symlink-resolved).
Methods
Section titled “Methods”resolveForRead()
Section titled “resolveForRead()”resolveForRead(
requestedPath):Promise<string>
Defined in: packages/tools/src/file/jail.ts:90
Resolve requestedPath to an absolute, symlink-resolved path for a read. The file
must already exist. Relative paths resolve against FileJail.cwd; absolute paths
are accepted when they fall within the read policy. Throws AdlError("INVALID_INPUT", …)
if the path escapes the read bound, is denied, or doesn’t exist.
Parameters
Section titled “Parameters”requestedPath
Section titled “requestedPath”string
Returns
Section titled “Returns”Promise<string>
resolveForWrite()
Section titled “resolveForWrite()”resolveForWrite(
requestedPath):Promise<string>
Defined in: packages/tools/src/file/jail.ts:100
Resolve requestedPath to an absolute, symlink-resolved path for a write. The parent
directory must already exist; the leaf may be missing. When the leaf itself already
exists, it is realpath’d too so an outbound leaf symlink cannot smuggle a write (or an
editFile read) outside the write bound. A missing leaf stays parent-only. Absolute
paths are allowed when they fall under allowWrite. Throws
AdlError("INVALID_INPUT", …) if the path is denied, outside the write allow list, or
its parent directory doesn’t exist.
Parameters
Section titled “Parameters”requestedPath
Section titled “requestedPath”string
Returns
Section titled “Returns”Promise<string>