This repository has been archived on 2026-03-13. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
greywall/docs/configuration.md
Mathieu Virbel da3a2ac3a4 rename Fence to Greywall as GreyHaven sandboxing component
Rebrand the project from Fence to Greywall, the sandboxing layer of the
GreyHaven platform. This updates:

- Go module path to gitea.app.monadical.io/monadical/greywall
- Binary name, CLI help text, and all usage examples
- Config paths (~/.config/greywall/greywall.json), env vars (GREYWALL_*)
- Log prefixes ([greywall:*]), temp file prefixes (greywall-*)
- All documentation, scripts, CI workflows, and example files
- README rewritten with GreyHaven branding and Fence attribution

Directory/file renames: cmd/fence → cmd/greywall, pkg/fence → pkg/greywall,
docs/why-fence.md → docs/why-greywall.md, example JSON files, and banner.
2026-02-10 16:00:24 -06:00

9.3 KiB

Configuration

Greywall reads settings from ~/.config/greywall/greywall.json by default (or ~/Library/Application Support/greywall/greywall.json on macOS). Legacy ~/.greywall.json is also supported. Pass --settings ./greywall.json to use a custom path. Config files support JSONC.

Example config:

{
  "network": {
    "allowedDomains": ["github.com", "*.npmjs.org", "registry.yarnpkg.com"],
    "deniedDomains": ["evil.com"]
  },
  "filesystem": {
    "denyRead": ["/etc/passwd"],
    "allowWrite": [".", "/tmp"],
    "denyWrite": [".git/hooks"]
  },
  "command": {
    "deny": ["git push", "npm publish"]
  },
  "ssh": {
    "allowedHosts": ["*.example.com"],
    "allowedCommands": ["ls", "cat", "grep", "tail", "head"]
  }
}

Config Inheritance

You can extend built-in templates or other config files using the extends field. This reduces boilerplate by inheriting settings from a base and only specifying your overrides.

Extending a template

{
  "extends": "code",
  "network": {
    "allowedDomains": ["private-registry.company.com"]
  }
}

This config:

  • Inherits all settings from the code template (LLM providers, package registries, filesystem protections, command restrictions)
  • Adds private-registry.company.com to the allowed domains list

Extending a file

You can also extend other config files using absolute or relative paths:

{
  "extends": "./base-config.json",
  "network": {
    "allowedDomains": ["extra-domain.com"]
  }
}
{
  "extends": "/etc/greywall/company-base.json",
  "filesystem": {
    "denyRead": ["~/company-secrets/**"]
  }
}

Relative paths are resolved relative to the config file's directory. The extended file is validated before merging.

Detection

The extends value is treated as a file path if it contains / or \, or starts with .. Otherwise it's treated as a template name.

Merge behavior

  • Slice fields (domains, paths, commands) are appended and deduplicated
  • Boolean fields use OR logic (true if either base or override enables it)
  • Integer fields (ports) use override-wins semantics (0 keeps base value)

Chaining

Extends chains are supported—a file can extend a template, and another file can extend that file. Circular extends are detected and rejected. Maximum chain depth is 10.

See templates.md for available templates.

Network Configuration

Field Description
allowedDomains List of allowed domains. Supports wildcards like *.example.com
deniedDomains List of denied domains (checked before allowed)
allowUnixSockets List of allowed Unix socket paths (macOS)
allowAllUnixSockets Allow all Unix sockets
allowLocalBinding Allow binding to local ports
allowLocalOutbound Allow outbound connections to localhost, e.g., local DBs (defaults to allowLocalBinding if not set)
httpProxyPort Fixed port for HTTP proxy (default: random available port)
socksProxyPort Fixed port for SOCKS5 proxy (default: random available port)

Wildcard Domain Access

Setting allowedDomains: ["*"] enables relaxed network mode:

  • Direct network connections are allowed (sandbox doesn't block outbound)
  • Proxy still runs for apps that respect HTTP_PROXY
  • deniedDomains is only enforced for apps using the proxy

Warning

Security tradeoff: Apps that ignore HTTP_PROXY will bypass deniedDomains filtering entirely.

Use this when you need to support apps that don't respect proxy environment variables.

Filesystem Configuration

Field Description
denyRead Paths to deny reading (deny-only pattern)
allowWrite Paths to allow writing
denyWrite Paths to deny writing (takes precedence)
allowGitConfig Allow writes to .git/config files

Command Configuration

Block specific commands from being executed, even within command chains.

Field Description
deny List of command prefixes to block (e.g., ["git push", "rm -rf"])
allow List of command prefixes to allow, overriding deny
useDefaults Enable default deny list of dangerous system commands (default: true)

Example:

{
  "command": {
    "deny": ["git push", "npm publish"],
    "allow": ["git push origin docs"]
  }
}

Default Denied Commands

When useDefaults is true (the default), greywall blocks these dangerous commands:

  • System control: shutdown, reboot, halt, poweroff, init 0/6
  • Kernel manipulation: insmod, rmmod, modprobe, kexec
  • Disk operations: mkfs*, fdisk, parted, dd if=
  • Container escape: docker run -v /:/, docker run --privileged
  • Namespace escape: chroot, unshare, nsenter

To disable defaults: "useDefaults": false

Command Detection

Greywall detects blocked commands in:

  • Direct commands: git push origin main
  • Command chains: ls && git push or ls; git push
  • Pipelines: echo test | git push
  • Shell invocations: bash -c "git push" or sh -lc "ls && git push"

SSH Configuration

Control which SSH commands are allowed. By default, SSH uses allowlist mode for security - only explicitly allowed hosts and commands can be used.

Field Description
allowedHosts Host patterns to allow SSH connections to (supports wildcards like *.example.com, prod-*)
deniedHosts Host patterns to deny SSH connections to (checked before allowed)
allowedCommands Commands allowed over SSH (allowlist mode)
deniedCommands Commands denied over SSH (checked before allowed)
allowAllCommands If true, use denylist mode instead of allowlist (allow all commands except denied)
inheritDeny If true, also apply global command.deny rules to SSH commands

Basic Example (Allowlist Mode)

{
  "ssh": {
    "allowedHosts": ["*.example.com"],
    "allowedCommands": ["ls", "cat", "grep", "tail", "head", "find"]
  }
}

This allows:

  • SSH to any *.example.com host
  • Only the listed commands (and their arguments)
  • Interactive sessions (no remote command)

Denylist Mode Example

{
  "ssh": {
    "allowedHosts": ["dev-*.example.com"],
    "allowAllCommands": true,
    "deniedCommands": ["rm -rf", "shutdown", "chmod"]
  }
}

This allows:

  • SSH to any dev-*.example.com host
  • Any command except the denied ones

Inheriting Global Denies

{
  "command": {
    "deny": ["shutdown", "reboot", "rm -rf /"]
  },
  "ssh": {
    "allowedHosts": ["*.example.com"],
    "allowAllCommands": true,
    "inheritDeny": true
  }
}

With inheritDeny: true, SSH commands also check against:

  • Global command.deny list
  • Default denied commands (if command.useDefaults is true)

Host Pattern Matching

SSH host patterns support wildcards anywhere:

Pattern Matches
server1.example.com Exact match only
*.example.com Any subdomain of example.com
prod-* Any hostname starting with prod-
prod-*.us-east.* Multiple wildcards
* All hosts

Evaluation Order

  1. Check if host matches deniedHostsDENY
  2. Check if host matches allowedHosts → continue (else DENY)
  3. If no remote command (interactive session) → ALLOW
  4. Check if command matches deniedCommandsDENY
  5. If inheritDeny, check global command.denyDENY
  6. If allowAllCommandsALLOW
  7. Check if command matches allowedCommandsALLOW
  8. Default → DENY

Other Options

Field Description
allowPty Allow pseudo-terminal (PTY) allocation in the sandbox (for MacOS)

Importing from Claude Code

If you've been using Claude Code and have already built up permission rules, you can import them into greywall:

# Preview import (prints JSON to stdout)
greywall import --claude

# Save to the default config path
greywall import --claude --save

# Import from a specific file
greywall import --claude -f ~/.claude/settings.json --save

# Save to a specific output file
greywall import --claude -o ./greywall.json

# Import without extending any template (minimal config)
greywall import --claude --no-extend --save

# Import and extend a different template
greywall import --claude --extend local-dev-server --save

Default Template

By default, imports extend the code template which provides sensible defaults:

  • Network access for npm, GitHub, LLM providers, etc.
  • Filesystem protections for secrets and sensitive paths
  • Command restrictions for dangerous operations

Use --no-extend if you want a minimal config without these defaults, or --extend <template> to choose a different base template.

Permission Mapping

Claude Code Greywall
Bash(xyz) allow command.allow: ["xyz"]
Bash(xyz:*) deny command.deny: ["xyz"]
Read(path) deny filesystem.denyRead: [path]
Write(path) allow filesystem.allowWrite: [path]
Write(path) deny filesystem.denyWrite: [path]
Edit(path) Same as Write(path)
ask rules Converted to deny (greywall doesn't support interactive prompts)

Global tool permissions (e.g., bare Read, Write, Grep) are skipped since greywall uses path/command-based rules.

See Also