Feature: Landlock sandbox directives for PreToolUse hooks

Resolved 💬 1 comment Opened May 10, 2026 by inspicere Closed Jun 9, 2026

Summary

PreToolUse hooks can perform static analysis on Bash commands before execution, but several bypass classes are fundamentally unsolvable by static analysis: shell function indirection (r() { cat "$1"; }; r .env), bash array expansion, runtime path construction, and write-then-execute attacks. These all construct or resolve file paths at runtime, making them invisible to any pre-execution text parser.

Linux Landlock LSM (available unprivileged since kernel 5.13, ABI v6 on modern kernels) solves all of these at the kernel level by restricting open() syscalls regardless of how the path was derived. However, the current hook architecture can't leverage it because hooks run as separate processes that exit before the command executes — Landlock restrictions only apply to the calling process and its descendants.

Proposal

Add support for hooks to return a sandbox directive that Claude Code applies to the Bash command's execution environment. Specifically:

{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "sandbox": {
      "landlock_deny_read": [
        "/home/user/.env",
        "/home/user/.vault-token",
        "/home/user/.ssh"
      ]
    }
  }
}

When Claude Code receives this response from a PreToolUse hook, it would:

  1. Create a Landlock ruleset handling LANDLOCK_ACCESS_FS_READ_FILE
  2. Grant read access to all filesystem paths EXCEPT those listed in landlock_deny_read
  3. Apply prctl(PR_SET_NO_NEW_PRIVS) and landlock_restrict_self() to the Bash child process before exec
  4. Execute the Bash command in the restricted environment

Why this matters

I maintain a PreToolUse secret-protection hook (~1450 lines of Python) that blocks Bash commands accessing sensitive files. After three rounds of multi-agent red team testing (8 parallel agents each round), we've identified and fixed 33 bypass vectors — but 5 architectural gaps remain that no amount of static analysis can solve:

| Gap | Example | Why static analysis fails |
|-----|---------|--------------------------|
| Shell function indirection | r() { cat "$1"; }; r .env | Function body is opaque |
| Array expansion | a=(cat .env); "${a[@]}" | Array contents not trackable |
| Runtime path construction | python3 -c "open(os.path.join(...))" | No .env in command text |
| Write-then-execute | Write script, run it | Script constructs paths at runtime |
| Symlink TOCTOU | Repoint symlink between check and exec | Race condition |

I built a working Landlock prototype that blocks all five. In testing, r() { cat "$1"; }; r .env returns Permission denied while echo hello and ls /tmp work normally. The missing piece is the bridge between the hook's decision and the command's execution context.

Alternative: SHELL override

A simpler approach: if Claude Code honors the SHELL environment variable (or provides a configuration option for the shell binary), users could point it at a wrapper script that applies Landlock before execing bash. This requires no Claude Code code changes but is less elegant and harder to configure.

Technical details

  • Landlock ABI v6 is available on kernel 6.1+ (Debian 13, Ubuntu 24.04+, Fedora 39+)
  • No privileges requiredlandlock_restrict_self() works for unprivileged users
  • Overhead: ~2ms for ruleset creation (one-time per command)
  • Compatibility: gracefully degrades on kernels without Landlock (hook falls back to static analysis only)
  • Rules use the "allowlist" approach: handle READ_FILE, grant read to everything except denied paths. This requires walking the filesystem to enumerate allowed paths, with transitive ancestor computation for directories containing sensitive files.

Scope

This proposal focuses on Landlock filesystem restrictions because they directly address the most common hook use case (protecting sensitive files). Future extensions could include:

  • landlock_deny_write: prevent writing to protected paths
  • seccomp_deny_syscalls: restrict specific syscalls (network, ptrace, etc.)
  • landlock_deny_net: restrict network access (Landlock ABI v4+)

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗