Skip to content

rogerchappel/pathsafe

pathsafe

pathsafe is a tiny local-first TypeScript CLI and library for answering one safety question before a tool touches disk: is this path allowed inside this root, and why?

It is designed for CLIs, generators, local agents, and file tools that need deterministic path-boundary checks with readable decisions.

Features

  • Explicit root containment checks
  • Allow and deny globs, with deny precedence
  • Symlink policies: follow, refuse, or ignore
  • .pathsafe.json config loading
  • JSONL batch checks
  • Explainable decision objects with reason codes
  • Dependency-light TypeScript library and CLI

Install

npm install pathsafe

For local development:

npm install
npm test

CLI

pathsafe check ./src/index.ts --root . --allow 'src/**' --deny '**/*.secret'

Human output:

ALLOW ./src/index.ts (src/index.ts): ALLOW_MATCH - Allowed by pattern src/**.

JSON output:

pathsafe check ./src/index.ts --root . --allow 'src/**' --json

Batch JSONL:

{"path":"src/index.ts"}
{"path":"../outside.txt"}
pathsafe batch --root . --input batch.jsonl --json

Config

Create .pathsafe.json:

{
  "root": ".",
  "allow": ["src/**", "docs/**", "README.md"],
  "deny": ["**/.env", "secrets/**"],
  "symlinkPolicy": "refuse"
}

CLI flags override config values.

Library

import { checkPath } from "pathsafe";

const decision = checkPath("src/index.ts", {
  root: process.cwd(),
  allow: ["src/**"],
  deny: ["**/*.secret"],
  symlinkPolicy: "refuse"
});

if (!decision.ok) {
  console.error(decision.reason, decision.message);
}

Symlink policies

  • follow (default): use the real path when possible and enforce containment on the resolved target.
  • refuse: deny if any existing path segment is a symlink.
  • ignore: evaluate the lexical path without resolving symlinks.

Use refuse for conservative file-write tools. Use follow when reading existing files and you want target containment. Use ignore only when a caller has already handled symlink risk.

Reason codes

  • ALLOW_MATCH
  • DENY_MATCH
  • NO_ALLOW_MATCH
  • OUTSIDE_ROOT
  • SYMLINK_REFUSED
  • INPUT_MISSING
  • ROOT_MISSING
  • CONFIG_ERROR

Security model

pathsafe is a local validation helper, not an OS sandbox. It does not provide kernel isolation, ACL management, or race-free filesystem authorization. For sensitive writes, validate as close as possible to the actual operation and prefer symlinkPolicy: "refuse".

About

Local-first TypeScript CLI and library for explainable path boundary checks

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors