Secure file reads
readSecureFile() is for absolute file paths that should be treated like credentials or other sensitive local inputs. It is stricter than fs.readFile() and different from root().read(): the file path is absolute, but the read is still fd-pinned and permission-checked before bytes are returned.
import { readSecureFile } from "@openclaw/fs-safe/secure-file";
const { buffer, realPath, permissions } = await readSecureFile({
filePath: "/var/lib/app/auth.token",
label: "auth token",
trust: { trustedDirs: ["/var/lib/app"] },
io: { maxBytes: 16 * 1024, timeoutMs: 5_000 },
});
#Checks
The helper:
- requires a local absolute path and rejects UNC/network paths by default
- rejects directories and, by default, symlink paths
- opens the file before reading and verifies the opened fd still matches the path and realpath
- optionally requires the real path to live under one of
trust.trustedDirs - rejects hard-to-verify or unsafe permissions unless
permissions.allowInsecureis set - rejects files owned by another POSIX uid
- enforces
maxBytesbefore and after reading - closes the handle on success, error, and timeout
On POSIX, unsafe permissions mean group/world writable, and group/world readable unless permissions.allowReadableByOthers is true. On Windows, the helper uses the ACL inspection helpers from permissions and refuses the read if ACLs cannot be verified.
#Options
type SecureFileReadOptions = {
filePath: string;
label?: string;
trust?: {
trustedDirs?: string[];
allowSymlink?: boolean;
allowNetworkPath?: boolean;
};
permissions?: {
allowInsecure?: boolean;
allowReadableByOthers?: boolean;
};
inject?: {
platform?: NodeJS.Platform;
env?: NodeJS.ProcessEnv;
exec?: PermissionExec;
};
io?: {
maxBytes?: number;
timeoutMs?: number;
};
};
permissions.allowInsecure is a migration escape hatch. Prefer fixing permissions and using formatPermissionRemediation to show the user what to run. trust.allowNetworkPath is off by default because UNC paths are remote authority, not local filesystem input. inject is for tests and platform adapters; production callers usually leave it unset.
#Errors
readSecureFile() throws FsSafeError with codes such as:
| Code | Meaning |
|---|---|
invalid-path | filePath was not a local absolute path. |
not-found | The path could not be stat'd before open. |
not-file | The opened target is not a regular file. |
symlink | The path is a symlink and trust.allowSymlink is false. |
path-mismatch | The path or realpath changed between open and verification. |
outside-workspace | realPath is outside trust.trustedDirs. |
permission-unverified | Required mode/ACL checks could not be completed. |
insecure-permissions | Mode bits or ACLs grant broader access than allowed. |
not-owned | POSIX owner uid is not the current process uid. |
too-large | File size or bytes read exceeded maxBytes. |
timeout | timeoutMs elapsed while reading. |
#See also
- Permissions — standalone POSIX mode and Windows ACL checks.
- Secret files — mode-0600 credential read/write helpers.
- Reading — root-bounded relative reads.