claw-wrap: Credential Isolation for Sandboxed CLI Tools Using Unix Socket Proxying
Hook
Your AI coding assistant just gained the ability to execute shell commands. How do you let it deploy to production without handing it your AWS keys?
Context
The rise of AI coding agents has created a paradox: these tools need access to privileged operations like deploying code, querying databases, or managing infrastructure, but they're fundamentally untrusted. A prompt injection attack or model hallucination could exfiltrate credentials within seconds. Traditional solutions fail here—environment variables are visible to any process, credential files can be read and copied, and even short-lived tokens can be stolen faster than they expire.
This isn't just an AI problem. CI/CD pipelines run third-party actions, development containers execute untrusted dependencies, and automated scripts pull code from external sources. The conventional approach of rotating credentials or scoping permissions assumes you can trust the execution environment itself. But when that assumption breaks—when the code running inside your sandbox is adversarial or compromised—you need a different security model: one where credentials never enter the untrusted boundary at all.
Technical Insight
claw-wrap solves this through architectural isolation: credentials live outside the sandbox, and a privileged daemon executes commands on behalf of sandboxed clients. The design centers on three components: transparent CLI wrappers, Unix socket communication, and credential backend adapters.
The transparent wrapper works through symlink hijacking. Instead of calling /usr/bin/aws directly, you create a symlink at /sandbox/bin/aws that points to the claw-wrap client binary. When the sandboxed process executes aws s3 ls, the kernel invokes claw-wrap, which reads argv[0] to determine which tool was actually requested. It then constructs a request message containing the command, arguments, and environment variables, signs it with HMAC-SHA256 using a shared secret, and sends it over a Unix socket to the daemon running outside the sandbox.
// Simplified client request flow
func executeWrappedCommand() error {
toolName := filepath.Base(os.Args[0])
request := &CommandRequest{
Tool: toolName,
Args: os.Args[1:],
Env: os.Environ(),
Timestamp: time.Now().Unix(),
}
// Sign with shared secret
mac := hmac.New(sha256.New, []byte(sharedSecret))
mac.Write(request.Serialize())
request.Signature = mac.Sum(nil)
// Send to daemon over Unix socket
conn, _ := net.Dial("unix", "/var/run/claw-wrap.sock")
defer conn.Close()
json.NewEncoder(conn).Encode(request)
// Stream response back to caller
io.Copy(os.Stdout, conn)
}
The daemon receives this request, validates the HMAC signature to prevent tampering, checks timestamp freshness to prevent replay attacks, and consults its policy engine. Policies are regex-based rules that can block dangerous commands—for instance, you might allow aws s3 cp but block aws iam create-user. If the command passes validation, the daemon queries the configured credential backend.
This is where the pluggable architecture shines. claw-wrap ships with adapters for pass (the Unix password manager), macOS Keychain, 1Password CLI, HashiCorp Vault, AWS Secrets Manager, and environment variable pass-through. Each adapter implements a simple interface: given a credential identifier (like aws/production/deploy-key), return a map of environment variables or HTTP headers. The daemon injects these into the execution environment, spawns the real binary (not the symlink), and streams stdout/stderr back through the socket to the client.
# Example daemon configuration
tools:
- name: aws
binary: /usr/local/bin/aws
credentials:
backend: vault
path: secret/aws/production
mapping:
AWS_ACCESS_KEY_ID: access_key
AWS_SECRET_ACCESS_KEY: secret_key
policies:
- allow: "^(s3|ec2|lambda)"
- deny: "iam"
- deny: ".*--output\\s+json.*\\|.*"
- name: curl
binary: /usr/bin/curl
mode: http-proxy
credentials:
backend: 1password
item: "GitHub API Token"
inject: header
header-name: Authorization
header-format: "token {value}"
The HTTP proxy mode deserves special attention. Some tools don't accept credentials via environment variables—they expect HTTP Authorization headers or bearer tokens. For these cases, claw-wrap can act as a man-in-the-middle proxy. The client sets HTTP_PROXY to the daemon's address, and the daemon intercepts outbound requests, injects credentials into headers, and forwards traffic. This works transparently with any HTTP client.
The Unix socket choice is deliberate. Unlike TCP sockets, Unix domain sockets respect filesystem permissions—you can restrict access to specific UIDs or GIDs. This means even if an attacker compromises the sandbox, they can only communicate with the daemon if the socket permissions allow it. Combined with HMAC authentication, this creates layered defenses: the attacker needs both filesystem access to the socket and knowledge of the shared secret.
Rate limiting adds another layer. The daemon tracks request counts per tool and time window. If a sandboxed process suddenly executes 1000 AWS commands per second—likely indicating automated exfiltration attempts—the daemon throttles or blocks further requests. This doesn't prevent all attacks, but it raises the cost of credential abuse significantly.
Gotcha
The symlink approach has inherent fragility. If your sandboxed code constructs absolute paths to binaries (/usr/bin/aws instead of aws), the wrapper never intercepts the call. You need to control PATH environment variables carefully and audit code for hardcoded paths. Some tools—particularly those distributed as statically linked binaries or using non-standard execution models—won't work correctly when invoked through the wrapper.
Regex-based policy enforcement is fundamentally weak against determined attackers. Command-line tools have infinite variations, escaping mechanisms, and encoding tricks. An attacker might run aws iam create-user as aws "i""a""m" create-user or encode arguments in base64. While the policies catch unsophisticated attempts, they're not cryptographic access controls. You're layering heuristics on top of tools that weren't designed with this security model in mind. For true protection, you'd need to parse and validate the actual tool semantics—an impossible task for arbitrary CLI tools.
The Unix socket limitation also creates operational challenges. If you're running sandboxes in containers or VMs, you need to mount the socket path into each environment. This works fine for Docker with volume mounts, but becomes awkward with Kubernetes sidecars or fully isolated VMs. Some teams work around this by running the daemon inside each container, but that defeats the isolation purpose—credentials are back inside the sandbox. Others use SSH tunneling or network proxies, which reintroduce network-level attack surfaces that Unix sockets were meant to avoid.
Verdict
Use if: You're running untrusted or semi-trusted code that requires privileged tool access—AI agents, CI/CD with third-party actions, automated scripts from external sources, or development environments with contractors. The setup overhead is justified when prompt injection, supply chain attacks, or insider threats are realistic concerns, and when credential rotation alone doesn't provide sufficient protection. claw-wrap excels in scenarios where you need audit trails of tool usage and can tolerate the operational complexity of managing daemon configurations and symlink hierarchies.
Skip if: You're working in fully trusted environments where all code is vetted, or if your threat model doesn't include process-level compromise. The architectural complexity isn't worth it for personal projects, small teams with strong code review, or systems where IAM roles and short-lived credentials already provide adequate security. Also skip if your tools don't follow standard CLI patterns or if you need to support Windows environments (Unix sockets are POSIX-only). For simpler use cases, environment-based secret injection tools like teller or summon offer 80% of the benefit with 20% of the complexity.