Skip to content

AgentSafeFS

CI License: Apache-2.0 Node.js >=22 Latest release

Guarded filesystem writes for AI agents, coding assistants, MCP tools, and automation.

CLI · API · Threat model · Security · Code signing policy · Privacy · Contributing · Discussions

AgentSafeFS is a security-focused Node.js library and standalone CLI that makes AI-driven file writes explicit, reviewable, conflict-aware, auditable, and rollback-capable. The library has no runtime dependencies.

It is designed for agentic AI, coding assistants, MCP servers, developer tools, and automation that need to modify a workspace without casually escaping the intended root or overwriting newer data.

Why AgentSafeFS

  • AI-agent filesystem safety — separates propose from commit so writes can be inspected and approved.
  • Path traversal defense — blocks .., unsafe absolute paths, symlink/junction escapes, hard-link targets, and common Windows path aliases.
  • Stale-write protection — hashes targets at proposal time and revalidates before mutation.
  • Safer mutation pipeline — sibling temp file, fsync, atomic rename where the platform permits it, and SHA-256 readback verification.
  • Rollback with integrity checks — restores only when snapshots and current target state still match expectations.
  • Audit-friendly — optional fsynced JSONL audit events without file contents or absolute workspace paths.
  • Cross-platform CI — tested on Windows, Linux, and macOS with Node.js 22 and 24.

AgentSafeFS puts a narrow safety layer between an automated tool and a workspace. A write is split into an inspectable proposal and a separate commit step:

propose -> approve when required -> revalidate -> write -> verify -> audit -> optional rollback

The project intentionally does one thing: make individual file writes harder to perform accidentally, stale, or outside an intended workspace.

Status

0.2.0 adds a standalone CLI and native release binaries while keeping the security-focused API deliberately small. The API and CLI may still evolve before 1.0.0.

The package remains marked private: true to prevent accidental npm registry publication. GitHub Releases are the distribution source for the standalone binaries and package archive; the source repository is Apache-2.0 licensed.

What it protects against

  • .. traversal and absolute paths outside the configured root
  • directory symlink and Windows junction escapes, including through non-existing descendants
  • writes through existing hard-linked targets
  • common Windows path aliases: NTFS ADS, 8.3 short-name aliases, reserved device names, trailing-dot/space aliases, and device namespaces
  • case-variant policy bypasses on Windows
  • secret-like filenames such as .env, key files, and token/credential-looking names
  • stale writes when the target changed after proposal
  • unapproved writes to protected paths or script/executable-like extensions
  • mutation of returned proposal objects or constructor policy inputs
  • repeated commit calls and expired proposals
  • rollback over newer third-party data
  • corrupted, hard-linked, or replaced rollback snapshots
  • audit failures that occur after mutation: recovery is verified and refuses to overwrite a newer third-party change

Core properties

  • Workspace root must already exist and may not itself be a symlink/junction.
  • Symlinks/junctions anywhere in a guarded target path are denied rather than followed.
  • Existing hard-linked files are always denied.
  • proposeWrite() never mutates the target.
  • Approval is bound to the same canonical target, not merely a free-form acknowledgement. On POSIX, confirmation remains exact-case even when policy matching is configured case-insensitively.
  • The target is hashed at proposal time and checked again immediately before mutation.
  • Writes use a sibling temporary file, fsync, rename, and readback SHA-256 verification.
  • Existing POSIX mode bits are preserved. New POSIX files default to 0600 unless newFileMode is configured.
  • Previous bytes are snapshotted before overwrite and verified by hash before rollback.
  • Internal transaction/configuration state uses JavaScript private fields.
  • Optional audit events are JSONL and do not include file contents or absolute workspace paths.
  • No runtime dependencies.

Standalone CLI

AgentSafeFS can be used without installing Node.js. GitHub Releases publish native single-file executables built from the same guarded-write engine:

Platform Asset
Windows x64 agentsafefs-windows-x64.exe
Windows ARM64 agentsafefs-windows-arm64.exe
Linux x64 agentsafefs-linux-x64
Linux ARM64 agentsafefs-linux-arm64
macOS Intel agentsafefs-macos-x64
macOS Apple Silicon agentsafefs-macos-arm64

Example on Windows:

.\agentsafefs-windows-x64.exe doctor --root C:\workspace
.\agentsafefs-windows-x64.exe plan --root C:\workspace --target notes.txt --text "hello"
.\agentsafefs-windows-x64.exe write --root C:\workspace --target notes.txt --text "hello"

Higher-risk writes do not accept a generic --yes. They require the exact guarded target through --approve <path>. Use --json for automation and MCP/tool integration. Configuration files are loaded only when explicitly selected with --config, avoiding silent repository-controlled policy changes.

Release assets include SHA-256 checksums, an SPDX SBOM, and GitHub build-provenance attestations. See docs/CLI.md for commands, exit codes, configuration, verification, and platform signing notes.

Code signing policy

AgentSafeFS is applying to the SignPath Foundation free Open Source code-signing program for Windows Authenticode signing. Free code signing provided by SignPath.io, certificate by SignPath Foundation once the application is approved and the signing integration is enabled. Until then, Windows release notes explicitly identify the binaries as unsigned. See CODE_SIGNING_POLICY.md and PRIVACY.md.

Library quick start from a clone

Requires Node.js 22+.

npm test
import { AgentSafeFS } from './src/index.mjs';

const safeFs = new AgentSafeFS({
  root: 'C:/workspace',
  auditPath: '.agentsafefs/audit.jsonl',
  policy: {
    immutable: ['vendor'],
    protectedPaths: ['config'],
    sensitiveAreas: ['infra'],
  },
});

const proposal = safeFs.proposeWrite({
  path: 'notes.txt',
  content: 'hello\n',
});

console.log(proposal.risk);

const result = safeFs.commit(proposal.operationId, {
  confirmedPath: proposal.risk.requiresApproval ? proposal.path : null,
});

console.log(result.sha256After);

If notes.txt changes after proposeWrite() and before commit(), the commit fails with CONFLICT_CHANGED_SINCE_PROPOSE instead of blindly overwriting the newer bytes.

Approval example

Script/executable-like extensions and configured protected areas are approval-required by default:

const proposal = safeFs.proposeWrite({
  path: 'scripts/deploy.ps1',
  content: '# ...',
});

// Throws APPROVAL_REQUIRED:
safeFs.commit(proposal.operationId);

// Confirmation must resolve to the same target:
safeFs.commit(proposal.operationId, {
  confirmedPath: proposal.path,
});

Rollback

safeFs.rollback(proposal.operationId, {
  confirmedPath: proposal.path,
});

Rollback is fail-closed. If the target changed after the commit, or if the snapshot no longer has the expected hash, rollback refuses to overwrite the current data.

Rollback metadata is held in memory, so rollback currently requires the same AgentSafeFS instance that performed the commit. Snapshot bytes are stored on disk under the configured snapshot directory. The CLI therefore does not advertise rollback across separate invocations. Long-running integrations should also define their own snapshot-retention and audit-log rotation policy after rollback is no longer required.

Important limits

AgentSafeFS is not an OS sandbox or permission boundary. Code that can bypass AgentSafeFS and call the filesystem directly still has whatever permissions the operating system gives it.

The library performs repeated path validation to close static and common replacement attacks, but Node.js does not provide a portable openat/directory-handle transaction primitive for this design. A hostile independent local process that can rewrite directory structure in the tiny interval between the final validation and rename is outside the current threat model. Recovery paths use their own content-hash checks so a newer third-party change is not intentionally overwritten during recovery. See docs/THREAT_MODEL.md.

The audit log is fsynced JSONL, not a cryptographically tamper-evident ledger and not an atomic transaction with the target file; a crash or low-level audit I/O failure can leave a partial/uncertain final audit record. Snapshots preserve file bytes; extended ACLs, xattrs, ownership changes, and timestamps are not a rollback contract.

API and policy

See docs/API.md.

Tests

npm test

The suite covers Windows junctions and path aliases, hard links, stale writes, policy/approval behavior, snapshot tampering, rollback conflicts, audit recovery, binary data, CLI approval behavior, JSON output, config handling, and non-mutating plans. CI runs across Windows, Linux, and macOS.

Security

Please read SECURITY.md before reporting a vulnerability.

Scope

AgentSafeFS is deliberately filesystem-only. See SCOPE.md.

License

Apache License 2.0. See LICENSE.

About

Security-focused Node.js library + standalone CLI for guarded filesystem writes by AI agents, coding assistants and MCP tools — exact approval, traversal defense, stale-write detection, audit and rollback.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages