Skip to main content

Permission Denied Errors

Symptom

Command fails with “Permission denied” or “Operation not permitted” errors.

Diagnosis

  1. Check what access was granted:
  2. Query capabilities from inside the sandbox:
  3. Run with verbose logging:

Common Causes

Sensitive Paths

These paths are blocked by default, even if a parent directory is allowed:
  • ~/.ssh/ - SSH keys
  • ~/.aws/ - AWS credentials
  • ~/.gnupg/ - GPG keys
  • ~/.kube/ - Kubernetes config
  • ~/.docker/ - Docker credentials
  • Shell history files
  • Shell configuration files
Why? These paths commonly contain secrets that an AI agent should never access. If you grant one of these paths with --allow, nono will warn you on macOS:
To intentionally access a blocked path, use --bypass-protection alongside your grant:

Stale File Grants (Linux)

On Linux, a file-level grant (--read-file, --write-file, --allow-file, or profile read_file/write_file/allow_file) attaches to the file’s inode at sandbox start, not to its path. If the file is later replaced atomically — the write-temp-then-rename() pattern used by editors, git config, systemd-resolved, and most config tools — the path points to a new inode that carries no rule, and access fails with EACCES for the rest of the session even though the grant still names the path. nono why detects this from inside the sandbox and reports it:
Remedies:
  • Restart the sandbox session — grants re-resolve to the current file.
  • If the file is rewritten routinely, grant its containing directory instead: directory rules cover files created after sandbox start, so they survive atomic replacement (at the cost of a broader grant).

Network Connection Failed

Symptom

Commands like curl, wget, or API calls fail with connection errors.

Possible Causes

  1. Network explicitly blocked - You used --block-net flag
  2. Actual network issue - DNS, firewall, or connectivity problem
  3. Application-specific issue - App needs specific configuration

Solutions

  1. If you used --block-net, remove it:
  2. Check if network is allowed from inside the sandbox:
  3. Test network outside nono:

Command Not Found

Symptom

or

Solutions

  1. nono not in PATH:
  2. Target command not in PATH:

Sandbox Initialization Failed

Symptom

Linux (Landlock)

  1. Check kernel version:
  2. Check Landlock is enabled:
  3. Enable Landlock (if missing): Add lsm=landlock,... to kernel boot parameters

macOS (Seatbelt)

  1. Check macOS version:
  2. Check for SIP issues: Some system integrity protection settings can interfere. This is rare.

Dry Run Shows Different Paths

Symptom

Paths in dry-run output don’t match what you specified.

Explanation

nono canonicalizes all paths:
  • Relative paths become absolute
  • Symlinks are resolved
  • .. and . are normalized
This is intentional to prevent symlink escape attacks.

Example


Child Process Doesn’t Inherit Sandbox

Symptom

You expect a child process to be sandboxed but it seems to have more access.

This Shouldn’t Happen

Child processes always inherit sandbox restrictions. If you’re seeing this:
  1. Verify the parent is sandboxed:
  2. Check if you’re testing correctly:
If you have a reproducible case where a child escapes the sandbox, please report it as a security issue.

Performance Issues

Symptom

Commands run slower under nono.

Explanation

There is minimal overhead from sandbox initialization (microseconds). If you’re seeing significant slowdowns:
  1. First run may be slower due to path canonicalization
  2. Many file operations may show overhead from kernel permission checks

Solutions

  • Grant access to larger directories instead of many individual files
  • Use --read for directories that don’t need write access (slightly faster path)

Using nono why --self for Debugging

When running inside a nono sandbox, you can query your own capabilities using nono why --self:
The --self flag reads the sandbox state from NONO_CAP_FILE, which is the only environment variable nono sets. This is designed for programmatic introspection by AI agents rather than debugging via shell variables.

Platform-Specific Issues

macOS: “killed: 9” or Immediate Termination

This usually means the Seatbelt profile was malformed. Run with -vvv to see the generated profile:

Linux: “Landlock not supported”

Your kernel may not have Landlock enabled. Check:

Linux: Network Restrictions Not Working

Network filtering requires Landlock ABI v4 (kernel 6.7+):

Discovering Required Paths

If you’re getting permission errors and aren’t sure which paths your application needs, run the command under nono run. nono reports denied paths at exit with suggested fix flags. When running with a profile it also prompts to save a patch:

Example Workflow

  1. Run your command — nono will sandbox it and report any denials at exit:
  2. If paths were blocked, nono reports them at exit with suggested fix flags:
  3. Re-run with the suggested flags, or accept the prompt to save them as a profile patch:

WSL2-Specific Issues

Sandbox initialization: EBUSY on seccomp

Symptom: Sandbox initialization failed with EBUSY when using --capability-elevation. Cause: WSL2’s init process (PID 1) installs its own seccomp user notification filter. The Linux kernel only allows one notify listener per filter chain, so nono’s attempt to install a second returns EBUSY. Solution: nono automatically disables capability elevation on WSL2. If you see this error, ensure you’re running a recent version. This is tracked in microsoft/WSL#9548.

Credential proxy refused on WSL2

Symptom: WSL2: proxy-only network mode cannot be kernel-enforced Cause: The proxy’s network lockdown depends on seccomp notify or Landlock V4, neither of which is available on WSL2. Solutions:
  • Use --env-credential instead of --credential (env var injection works normally)
  • Opt in to degraded proxy mode with wsl2_proxy_policy: "insecure_proxy" in your profile’s security config (details)

Per-port network filtering unavailable

Symptom: --open-port or --listen-port fails on WSL2. Cause: Landlock V4 (kernel 6.7+) is required for TCP port filtering. WSL2 ships kernel 6.6. Solution: Use --block-net for full network isolation, or wait for a WSL2 kernel upgrade to 6.7+.

Verifying WSL2 compatibility

Run nono setup --check-only inside WSL2 to see the full feature availability matrix:
This reports the detected kernel version, Landlock ABI, WSL2 detection status, and which features are available.

Getting Help

If you’re still stuck:
  1. Search existing issues: GitHub Issues
  2. Open a new issue with:
    • nono version (nono --version)
    • OS and kernel version
    • Full command that failed
    • Error message
    • Output of nono run --dry-run with same flags