Reference

Secure file reads

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.allowInsecure is set
  • rejects files owned by another POSIX uid
  • enforces maxBytes before 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:

CodeMeaning
invalid-pathfilePath was not a local absolute path.
not-foundThe path could not be stat'd before open.
not-fileThe opened target is not a regular file.
symlinkThe path is a symlink and trust.allowSymlink is false.
path-mismatchThe path or realpath changed between open and verification.
outside-workspacerealPath is outside trust.trustedDirs.
permission-unverifiedRequired mode/ACL checks could not be completed.
insecure-permissionsMode bits or ACLs grant broader access than allowed.
not-ownedPOSIX owner uid is not the current process uid.
too-largeFile size or bytes read exceeded maxBytes.
timeouttimeoutMs 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.