Back home
Open Source MIT, open source on GitHub

file-guard: per-process access control for credential files

Problem

Env-injection vaults cover programs you can launch under a wrapper, but they do not cover the long tail of tools that insist on writing their own plaintext credentials to disk and reading them back themselves. That is the real attack surface for supply-chain secret theft: malicious code in a dependency runs with your uid and quietly reads ~/.aws/credentials, the gcloud config, SSH keys, or a CLI token store, then exfiltrates them. Permissions are no defense, because the attacker is you as far as the kernel is concerned.

What we did

file-guard mounts a read-write FUSE file at the credential path. On every open() it resolves the calling process from the FUSE request, identifies the binary via /proc/<pid>/exe, and evaluates a policy in the direction of access: real contents only to binaries you have authorized, EACCES or an interactive prompt otherwise. Identity is pinned hard: an allow-always rule pins the binary sha256, so a package upgrade or a swapped-in binary re-prompts instead of silently inheriting the grant; interpreter rules additionally pin the entry script path and its content hash, so python running gcloud does not bless every other script. Session grants are bound to pid plus process start_time, so a recycled PID cannot inherit a one-time allow. The root daemon has no display, so prompts go to a session agent over a systemd socket-activated unix socket with a peer-cred uid check. Authorized writes are buffered per handle and persisted on close, so tools need no reconfiguration. It targets the real supply-chain surface: malicious dependency code running as you, quietly reading credential files off disk.

Result

file-guard is about 4,300 lines of Rust, with formatting, linting, tests, and a reproducible Nix build enforced on every change. It ships drop-in config for eight credential-writing tools (aws, gcloud, docker, kubectl, gh, npm, ssh, and the Claude Code CLI) and a structured, queryable audit log of every access. We dogfood it ourselves: it runs on our own laptops, gating real cloud credential files behind a desktop prompt.

Key highlights

  • FUSE interception authorizes every open() against policy by resolving the caller PID from the FUSE request, EACCES on deny
  • Identity that re-prompts on change: pins the binary sha256, plus an interpreter entry-script path and content hash
  • Recycle-proof session grants keyed on pid plus process start_time, so a reused PID cannot inherit a one-time allow
  • Root-anchored prompt agent over a systemd socket-activated unix socket with a peer-cred uid check
  • Tightly scoped to the supply-chain threat that matters: dependency code reading your credential files as you

Tech stack

RustFUSE (fuser)tokiosystemd socket activationNix flake + NixOS modulecargo-deb