Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.clawker.dev/llms.txt

Use this file to discover all available pages before exploring further.

AI coding agents are not traditional CLI tools. They make autonomous decisions about what files to read and write, what commands to run, what network requests to make, and what credentials to use. They do this with full conviction — even when they’re wrong. They hallucinate file paths, lose context mid-task, get tunnel vision on a broken approach, and can be coerced by adversarial content embedded in the data they fetch. Handing one of these agents unrestricted code execution, full filesystem access, and open network on your bare-metal host is reckless. Clawker exists because containers have been solving this problem for over a decade. The agent runs inside a Docker container where it can thrash, experiment, and make mistakes freely — that’s the whole point of a devcontainer. What matters is that the blast radius stops at the container boundary. The host filesystem, credentials, and network are protected by default, and every capability is restricted until you explicitly open it. This page maps the attack surfaces to clawker’s security controls. For configuration details and CLI commands, follow the cross-references to the dedicated guides.

Threat Actors

Clawker’s security model is designed around two threat actors: The agent itself. An LLM-powered coding agent is autonomous software that can hallucinate file paths, run destructive commands, or pursue the wrong goal with absolute confidence. It doesn’t need to be malicious to cause damage — context window amnesia, tunnel vision, and overconfident tool use are enough. The agent might rm -rf a directory it shouldn’t touch, push code to the wrong branch, or install packages that compromise the environment, all while believing it’s doing exactly what you asked. Cybercriminal Prompters. This might seem facetious, or an oversimplification, but when you distill it down basically any external entity is trying to coerce your agent via prompt injection. There are a myriad of subcategories and motivations here but the same controls deal with all of them.

Attack Vectors

Prompt injection

Adversarial content embedded in web pages, README files, package metadata, API responses, or files hosted on cloud storage can hijack the agent’s intent. A malicious instruction hidden in a fetched document could direct the agent to exfiltrate source code, steal credentials, or modify files in ways that serve the attacker rather than the user. The agent cannot reliably distinguish legitimate instructions from injected ones. Clawker does not attempt to prevent prompt injection — and this is a deliberate design choice. LLMs can develop their own specialized internal languages — often referred to as “cryptoglyphs” or “internal representations” — which are highly efficient, non-human, mathematical, or symbolic languages. They can also interpret ancient Hebrew, binary, base64, steganographic patterns, and every other human or machine dialect in history. Trying to filter or detect injected instructions is boiling the ocean (actually, boiling the ocean might be easier). Similarly, clawker does not attempt to inspect egress traffic for sensitive content. Building what amounts to a reverse WAF that can detect whether an outgoing request — across all protocols, all ports, of any size — contains something sensitive is equally fruitless. HTTP has no technical size limit on request bodies, and other protocols vary or have none at all. Scanning every byte of outbound traffic hoping to detect a highly obfuscated and encrypted payload that might contain sensitive data would make the system unusable. Even large WAF vendors cap their request scanning buffers to small allocations (typically 128KB max) because full-payload inspection at scale is impractical. The payload could be a tar archive of base64-triple-encoded text containing secrets, double-encrypted, split across multiple requests, or disguised as legitimate API traffic. Content-based exfiltration detection is an arms race you cannot win. Enlisting another LLM to review outbound requests doesn’t solve this either — it adds enormous latency to every network call and relies on a model that is vulnerable to the exact same coercion and precision problems as the agent it’s supposed to be watching. Instead, clawker takes the only approach that actually works: deny the connection entirely. If the agent gets coerced into exfiltrating data, the firewall blocks the egress — it doesn’t matter what’s in the payload because the payload never leaves. If it gets coerced into destructive file operations, container isolation limits the blast radius to the mounted workspace. The injection can change the agent’s intent, but it can’t change the container’s constraints.

Supply Chain Security

The clawker project leverages every version pinning and integrity check opportunity in CI, its infra containers, and embedded Dockerfile template. SCA and SAST scanning checks are used in CI. The release pipeline specifically:
  • Immutable CI inputs. All GitHub Actions and tool binaries are pinned to exact versions or SHA commit hashes, not mutable version tags. Go dependencies are integrity-checked via go.sum checksums. The Dockerfile used to build the embedded firewall and control-plane infrastructure image (Dockerfile.controlplane) is pinned to a SHA256 digest of its base image, so an attacker cannot substitute a tampered base image by re-tagging upstream.
  • Pinned BPF toolchain. The BPF object files are produced by clang+llvm-strip from the Ubuntu 24.04 (Noble) apt repos, pinned to exact versions in the Makefile’s BPF_APT_DEPS variable (see the Makefile for current pins). CI’s sudo make bpf-deps step (on the pinned ubuntu-24.04 runner) and the macOS-developer Dockerfile.controlplane (which builds on a SHA256-pinned ubuntu:24.04 base) install from the same list — the Makefile is the single source of truth, so version bumps update both paths atomically.
  • Deterministic build inputs. Binaries are compiled with CGO_ENABLED=0 (pure Go, no C toolchain), stripped (-s -w), and built with -trimpath via GoReleaser. Build metadata (version, commit date) is injected via ldflags at compile time from the tagged commit, not from wall-clock or host environment. Byte-identical reproduction across hosts is not a claimed property — the BPF bytecode is produced by a pinned-but-not-snapshotted apt closure on the pinned ubuntu-24.04 runner; the integrity story rests on signed attestations against the CI build, not local re-runs.
  • SHA256 checksums. GoReleaser generates a checksums.txt containing SHA256 hashes for every release artifact.
  • Cosign keyless signing. The checksums file is signed using Sigstore Cosign in keyless mode (OIDC identity from the GitHub Actions workflow). This produces a Sigstore bundle (checksums.txt.sigstore.json) published as a release asset. The signing identity anchors to the reusable workflow release-build.yml at the release tag, not the caller release.yml — see Verifying a release for the exact identity regex.
  • SBOM generation. A Software Bill of Materials is generated for every release archive using Syft (SPDX-JSON format) and published as a release asset alongside the archives.
  • GitHub artifact attestation. One SLSA v1 build-provenance attestation is produced per release via actions/attest@v4, covering sixteen subjects: the four release archives, the four primary clawker CLI binaries (linux/darwin × amd64/arm64), and the eight embedded Linux binaries (clawkerd, clawker-cp, ebpf-manager, coredns-clawker × amd64, arm64). The predicate is auto-generated by the action from GitHub Actions context — source commit, workflow ref, builder ID, runner environment. That source-commit binding transitively pins every reproducibility input in the repo: Makefile (BPF_APT_DEPS), Dockerfile.controlplane, .goreleaser.yaml, internal/controlplane/firewall/ebpf/gen.go (clang -cflags, bpf2go pin), BPF C sources, and the workflow YAMLs (with their pinned action SHAs). Anyone with a verified attestation can git checkout and inspect every input that affected output bytes. Same-repo SLSA Build L3 isolation is provided by GitHub’s reusable-workflow boundary: signing happens in the reusable workflow’s isolated job context, so the Fulcio cert SAN cryptographically binds to release-build.yml@refs/tags/<tag> and cannot be impersonated by any other workflow in this repo. Browse attestations at github.com/schmitthub/clawker/attestations.
  • Tag integrity. The release pipeline’s tag trigger is protected by a GitHub repository ruleset that restricts creation, update, and deletion of release tags to repository administrators and requires cryptographic signing. The workflow additionally validates that release tags match a valid semver pattern and that the tagged commit is an ancestor of main — rejecting malformed version tags, tags on feature branches, or tags on arbitrary commits. Together, these controls ensure that only authorized, signed release tags with valid version syntax pointing to reviewed code on the main branch can trigger a release.
  • Immutable releases. The tag ruleset prevents release tags from being deleted, moved, or force-pushed. Once a release is published, its artifacts, checksums, and attestations are frozen — a compromised CI pipeline cannot silently replace a previously published binary.
  • Branch rulesets. All commits require cryptographic signing on every commit. Branches can not be deleted. The main branch requires all merges to pass CI status checks (security scanning, linting, unit tests, license checks, generated docs freshness) and be approved by a code owner.
There is an inherent risk in using third-party packages and libraries during software development, especially recently. Clawker itself, Claude Code, and anything you put on your host machine or in your container could become a victim of complex supply chain attacks. Developing in containers does help keep your system safer, but it does not eliminate the risk.For example, if you had been using trivy or litellm in a container with restricted egress…trivy. The stolen data is encrypted using a hybrid AES-256-CBC + RSA scheme and bundled into a tpcp.tar.gz archive, then exfiltrated via HTTP POST to a typosquatted domain scan.aquasecurtiy[.]org.litellm. Stolen data is decoded then encrypted using AES-256-CBC with a randomly generated session key. That session key is subsequently encrypted using a hard-coded RSA public key embedded in the payload. The encrypted data and key are packaged into an archive (tpcp.tar.gz) and exfiltrated to a remote endpoint controlled by the attacker, including the domains models[.]litellm[.]cloud and checkmarx[.]zone.Regardless of how or if your container became infected, or what obfuscation and packaging they used… the exfiltration would have failed and cleaning the infection would involve simply building a new image with patched packages, and creating a fresh container.

Verifying a release

1. Download and checksum. Download a release archive and verify its SHA256 checksum against the published checksums.txt:
mkdir -p /tmp/verify && gh release download v0.7.6 --repo schmitthub/clawker \
  --pattern 'clawker_0.7.6_linux_arm64.tar.gz' \
  --pattern 'checksums.txt*' --dir /tmp/verify

cd /tmp/verify && sha256sum -c checksums.txt --ignore-missing
# clawker_0.7.6_linux_arm64.tar.gz: OK
2. Verify cosign signature on checksums. This proves the checksums file was signed inside the reusable build workflow at the exact tagged commit — not by a human, a compromised process, or any other workflow in this repo. Requires cosign v3+.
cosign verify-blob \
  --bundle /tmp/verify/checksums.txt.sigstore.json \
  --new-bundle-format \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  --certificate-identity-regexp '^https://github\.com/schmitthub/clawker/\.github/workflows/release-build\.yml@refs/tags/v[0-9]+\.[0-9]+\.[0-9]+(-[A-Za-z0-9._-]+)?(\+[A-Za-z0-9._-]+)?$' \
  /tmp/verify/checksums.txt
# Verified OK
The regex anchors to the reusable workflow release-build.yml (where the cosign sign step runs), not the caller release.yml. A substring-only regex like 'github\.com/schmitthub/clawker' would also match a forged attestation produced by any other workflow file in this repo. --new-bundle-format is required for bundles emitted by actions/attest@v4 (mediaType: application/vnd.dev.sigstore.bundle.v0.3+json); cosign v3 defaults to the legacy format and rejects v0.3 silently. 3. Verify SLSA build provenance attestation. GitHub’s verifier auto-fetches the signed bundle from the attestation store. Requires gh >= 2.49.
gh attestation verify /tmp/verify/clawker_0.7.6_linux_arm64.tar.gz \
  --owner schmitthub \
  --signer-workflow schmitthub/clawker/.github/workflows/release-build.yml
gh attestation verify returns no stdout on success — only an exit code. Add --format json | jq to surface the subject digest, builder ID, and signing identity.

Per-binary forensic verification

The SLSA build-provenance attestation covers sixteen subjects — the four release archives, the four clawker CLI binaries, and the eight embedded Linux binaries — so an investigator can verify any individual binary without re-downloading the archive. This matters when:
  • A long-running container holds a clawker-cp or clawkerd binary unpacked from a release months ago, and you want to confirm it has not been swapped under you.
  • You have only one of the four embedded Linux binaries from a forensic image and need to answer “which release did this come from, and is it intact?”
  • You are doing differential analysis after an incident and need to know which specific binary (if any) diverged from what was attested at build time.
The procedure is the same gh attestation verify call against the suspect binary — gh resolves the attestation by the binary’s sha256 digest. The signing identity is the reusable workflow at the release tag; the subject set inside the signed predicate must contain that binary’s sha256 digest or verification fails. To enumerate the attested inputs from the predicate alone (source commit, workflow ref, builder ID), dump the statement:
gh attestation verify /tmp/verify/clawker_0.7.6_linux_arm64.tar.gz --owner schmitthub \
  --signer-workflow schmitthub/clawker/.github/workflows/release-build.yml \
  --format json | jq '.[].verificationResult.statement.predicate.buildDefinition'
Every reproducibility input lives in the source tree at the attested commit — Makefile for the BPF apt pins, internal/controlplane/firewall/ebpf/gen.go for the bpf2go pin and clang flags, the workflow YAMLs for action SHAs. Resolve them via git show <commit>:<path> once you have the source commit from the attestation.

How the Firewall Works

The firewall is central to most of clawker’s threat mitigations, so it’s worth understanding the mechanism before diving into specific threats. All clawker containers run on a dedicated clawker-net bridge network, isolated from other Docker workloads and the host’s network. Only internal traffic is freely allowed, but Docker’s built-in DNS service discovery only resolves clawker’s own internal services (Envoy, CoreDNS, the control plane, the host proxy via host.docker.internal, and the optional monitoring stack). The network gateway — which routes to the host machine — is locked down separately: only the host proxy port is allowed through, and all other traffic to the gateway is redirected to Envoy and denied. This prevents the agent from reaching host services even though it has network-level access to the bridge subnet. Claude Code runs as an unprivileged claude user (UID 1001) inside the container. The container’s PID 1 is clawkerd, the per-container supervisor — it runs as root but never executes user-controlled code in its own process. Privilege drop to UID 1001 happens kernel-side between fork and exec via SysProcAttr.Credential, so there is no user-mode code path that briefly holds root before dropping it. eBPF cgroup programs that enforce the firewall are attached to the container’s cgroup from outside the container by the clawker control plane — agent containers themselves run fully unprivileged (cap_add: [], no NET_ADMIN, no NET_RAW). Per-container enforcement is keyed by presence in a global container_map BPF map. The TCP routing table (route_map) is itself global and keyed by {domain_hash, dst_port} — containers that are enrolled in container_map see enforcement, everything else passes through. Rule changes are pushed live via an ebpf-manager sync-routes call whenever clawker firewall add/remove/reload runs, so the data plane reflects new rules without restarting containers or the firewall stack. Per-domain TCP routing depends on a dns_cache BPF map that tracks ip → domain_hash for every A-record answer. Clawker ships a custom CoreDNS build with an in-tree dnsbpf plugin that writes to this map in real time on every successful DNS response. This replaces an earlier startup-time DNS seeding approach — seeding was vulnerable to DNS round-robin (CDN backends rotate faster than the firewall reloads), which could silently blackhole traffic to allowlisted domains. With the plugin, whatever IP the resolver hands the container has already been observed and hashed at the moment of connection. Only NOERROR responses with A records populate the map; NXDOMAIN and other failures are passed through untouched so blocked domains never leak in. The CoreDNS container runs with CAP_BPF + CAP_SYS_ADMIN and a /sys/fs/bpf bind mount — the minimum privileges required to open the pinned map and update it. This layered approach means traffic is controlled at the DNS level (unlisted domains never resolve), the TCP level (Envoy enforces SNI matching, protocol rules, and path-level restrictions), the UDP level (non-DNS UDP is blocked entirely), and the ICMP level (all outbound ICMP is dropped to prevent ICMP tunneling). IPv6 scope. The eBPF cgroup/connect6 program applies the full IPv4 routing pipeline (DNS redirect, gateway lockdown, per-domain route lookup, Envoy fallback) to IPv4-mapped IPv6 addresses (::ffff:x.x.x.x). This matters because most modern programs — ssh, curl, Node.js, Python — open dual-stack IPv6 sockets by default and connect to IPv4 targets via IPv4-mapped addresses. A prior implementation allowed all IPv4-mapped addresses through without enforcement, which was a silent dual-stack bypass for nearly every common tool; that gap is closed. Native IPv6 (connections to real IPv6 addresses such as 2606:4700::1, or traffic forced via -6) is denied — the egress listeners, DNS forward zones, and BPF maps are IPv4-only, and transparent native-IPv6 routing is not supported today. When the firewall is toggled off for a container (via clawker firewall disable), clawker updates the container’s DNS routing to Docker’s embedded DNS (127.0.0.11), which forwards externally to Cloudflare’s anti-malware DNS nameservers (1.1.1.2, 1.0.0.2). This provides a safety net — the agent gets unrestricted network access, but DNS still filters known-malicious domains. Re-enabling the firewall restores the routing to Envoy and CoreDNS. All egress traffic going through the firewall stack is visible in the Grafana dashboard when the monitoring stack is running, including domain, protocol, HTTP path, response codes, and DNS query details. (see: Monitoring) See the Firewall guide for the full architecture, configuration, and CLI reference.
Claude Code’s WebSearch tool uses Anthropic’s API to perform searches. This means the agent may appear to reach domains that are not in your allowlist via search results, but this is not a firewall bypass. The WebFetch tool, however, does go through the container’s network and is subject to the firewall.

Data Exfiltration via Network Egress

Threat: A prompt-injected or hallucinating agent sends source code, secrets, environment variables, or credentials to an attacker-controlled endpoint — or leaks sensitive data to unintended services. Attack surface: Any outbound network connection from the container. How clawker mitigates it:
  • Deny-by-default firewall. The Envoy+CoreDNS firewall blocks all outbound traffic. TCP is routed to Envoy via eBPF cgroup/connect4 for IPv4 and cgroup/connect6 for IPv4-mapped dual-stack IPv6, DNS is routed to CoreDNS, and non-DNS UDP is dropped entirely. Native IPv6 is denied outright (see IPv6 scope in How the Firewall Works). Traffic to the clawker-net CIDR is allowed (for Envoy, CoreDNS, and the optional monitoring stack), but everything else is deny-by-default. Only explicitly whitelisted domains on specific protocols are reachable. DNS queries for unlisted domains return NXDOMAIN — the domain never even resolves. When a known (cached) domain is reached on a port that has no matching rule, the connection falls through to Envoy’s egress listener where the deny chain resets it; earlier bypass paths through dual-stack IPv6 were closed as part of the cgroup/connect6 hardening.
  • Domain-based enforcement. Domains are whitelisted by name, not by IP address. This is critical — many domains sit behind shared CDN edges like Cloudflare, so IP-whitelisting one domain could accidentally open the entire internet. IPs also rotate frequently in load-balanced environments, making IP-based rules fragile. The proxy honors the requested domain but performs its own DNS resolution from the allowlist — the agent cannot influence where traffic actually goes. Connections to unlisted domains are rejected. A coerced agent that spoofs a whitelisted domain in its request headers while targeting an attacker-controlled IP still ends up at the real whitelisted service — the attacker’s IP is never contacted.
  • Path-level filtering. For domains that need fine-grained control, the proxy uses protocol inspection to enforce restrictions down to the HTTP path. You can allow a domain but restrict which endpoints are reachable — useful for scoping access on platforms that mix trusted and untrusted content (e.g., allow api.github.com/repos/ but block api.github.com/gists).
  • Minimal hardcoded allowlist. Only the domains required for Claude Code itself to function (API, OAuth, telemetry) are allowed by default. See the Security page for the canonical list. GitHub, npm, PyPI, and every other service must be explicitly added.
If docker support is enabled in your project’s configuration, Docker image pulls are handled by the host daemon, outside the container’s network namespace, and are not subject to the container firewall. See Docker Socket in the Shared Responsibility section for the implications of this and how to manage it.
  • DNS exfiltration prevention. DNS-based exfiltration is a well-known technique where stolen data is encoded into DNS queries — for example, resolving stolen-secret.attacker.com or encoding data as subdomains (dG9rZW4.exfil.attacker.com). This is often effective because DNS traffic is overlooked by network controls and even a single query can leak data. When the firewall is enabled, Clawker routes all DNS requests through the managed CoreDNS instance, which only has forward zones for whitelisted domains. Every other query — including crafted exfiltration subdomains — returns NXDOMAIN. There is no upstream resolver fallback (specific internal service names, like those for the monitoring stack, forward to Docker embedded DNS, meaning arbitrary service discovery is unavailable when the firewall is enabled). NXDOMAIN responses are never written to the eBPF dns_cache map, so a blocked domain cannot smuggle an attacker-controlled IP into the per-domain route table. When the firewall is disabled, the container resolves to Docker’s embedded DNS, which forwards to Cloudflare’s anti-malware DNS nameservers (1.1.1.2, 1.0.0.2).
  • Raw TCP port-level routing. TLS and HTTP carry domain metadata (SNI, Host header) that Envoy can inspect, allowing multiple domains per port. Raw TCP protocols like SSH have no such field — there’s nothing in the stream identifying the intended domain. IP-based rules are not viable because IPs rotate frequently behind CDNs and load balancers. Instead, clawker redirects all traffic on a given port to the whitelisted domain for that port. A proto: ssh rule for github.com on port 22 captures every outbound port 22 connection and routes it to GitHub — an attacker cannot reach an arbitrary SSH server. If multiple rules target the same port, the first rule wins. Multi-domain support for raw TCP ports is a tracked limitation. If you are pentesting clawker’s firewall: a successful TCP connect on a port with a whitelisted rule does not mean you reached your intended target. The connection was silently redirected to the whitelisted service. Verify by checking the remote banner or certificate before concluding you have egress.
  • ICMP blocked. ICMP tunneling tools (e.g., ptunnel, icmpsh) can exfiltrate data by encoding it in ICMP echo request/reply payloads. While slow (~50-100 KB/s), this is effective because ICMP is neither TCP nor UDP and is often overlooked by network controls. Clawker blocks raw socket creation via eBPF cgroup/sock_create, preventing ICMP tunneling entirely.
See the Firewall guide for the full architecture, configuration, and CLI commands.

Host Infection / Filesystem Damage

Threat: A hallucinating or coerced agent runs destructive commands (rm -rf, overwrites, corrupted writes), installs malicious or unapproved packages, accesses sensitive files on the host system — personal documents, SSH keys, system configuration, other projects. Attack surface: The host filesystem. How clawker mitigates it:
  • Container isolation. The agent runs inside a Docker container. The host filesystem is not mounted into the container by default — the agent has no awareness of or access to host system files, user files, tools, or other projects. They simply don’t exist from the agent’s perspective.
  • Controlled workspace mounting. The only host files the agent can touch are the ones the user explicitly mounts — either as a live bind mount or an ephemeral snapshot copy. Snapshot mode creates a disposable copy in a Docker volume, so changes never reach the host at all. In bind mode, the blast radius is limited to the mounted directory.
  • Version-controlled repositories. For git repositories, the damage from destructive file operations is largely mitigated by version control — the user can always reset, checkout, or recover from the git history.
  • Unprivileged user. The agent runs as a non-root user (claude:claude, UID 1001) inside the container. It cannot escalate privileges, modify system files within the container, or bypass file permission boundaries on mounted directories.
  • No host resource access. System tools, package managers, shell configuration, browser profiles, credential stores, and everything else on the host are outside the container boundary. The agent cannot install system-level packages, modify host shell config, or access other applications.
  • User-controlled secrets. Any secrets the container has access to (environment variables, env files, forwarded credentials) are explicitly provided by the user — and their exfiltration is mitigated by the network firewall.
See Container Internals for bind vs snapshot details and workspace configuration.
.clawkerignore and tmpfs overlays.Directories listed in .clawkerignore (e.g. node_modules/, vendor/, .venv/) are masked inside the container with empty tmpfs mounts mounted as root (macOS doesn’t support UID/GID settings) when in workspace.bind mode (snapshot ignores copying them). This prevents binary and dependency cross-contamination between host and container operating systems. Because of this the tmpfs mounts use the exec setting, overriding Docker’s default noexec, but nosuid and nodev are on by default.The noexec hardening pattern targets unattended ephemeral production containers where the entire root filesystem is read-only and tmpfs is the attacker’s only writable surface — restricting exec on /tmp and /dev/shm blocks the classic “download and execute” post-compromise chain. That threat model does not apply to a development container. In our case, the workspace bind mount already has exec. An attacker who can drop a binary to node_modules/ can just as easily drop it to the project root or src/. So noexec on the tmpfs overlays is a speed bump, not a barrier. The real controls are the egress firewall (prevents downloading payloads), the unprivileged user (prevents privilege escalation), and seccomp filtering (restricts dangerous syscalls).

Summary

ThreatPrimary ControlDefaultGuide
Data exfiltration (network + DNS)Network firewall + CoreDNS NXDOMAINOnFirewall
Data exfiltration (ICMP tunneling)eBPF sock_create blocks SOCK_RAWOnFirewall
Host filesystem damageContainer isolation + workspace mount scopingOnContainer Internals

Shared Responsibility

Clawker provides the guardrails, but your configuration choices determine your actual security posture. The controls above are only as strong as how you configure them.

Firewall Management

The firewall is your primary defense against data exfiltration. Every domain you add to the allowlist is attack surface you’re accepting. Be deliberate:
  • Avoid untrusted domains or domains with untrusted content. Storage buckets, UGC platforms, and gist-style services can host attacker-controlled content that your agent fetches — including prompt injection payloads. Use specific subdomains instead of top-level domains where possible, and leverage path rules to exclude endpoints that serve user-generated or untrusted content.
  • Don’t disable the firewall unless you’re in a trusted, isolated environment and accept fully unrestricted egress.

Credential Scoping

The credentials you inject via environment variables or env files are available to the agent for the entire session. Apply least privilege:
  • Scope tokens to the minimum permissions needed. If the agent only reads repositories, use a read-scoped GITHUB_TOKEN, not repo:write.
  • Avoid injecting long-lived secrets when short-lived or session-scoped tokens are available.
  • Review what your agent.env and agent.env_file entries expose before each session.

Docker Socket

Enabling security.docker_socket: true mounts the host Docker socket into the container. The Docker CLI inside the container is the real Docker CLI talking directly to your host Docker daemon — not Docker-in-Docker (which is resource-heavy and brittle). This means the agent has full, unfiltered control over your Docker daemon and can create, modify, and delete any container, image, or volume on your host.
Mounting the Docker socket is a major privilege escalation vector. The agent gains root-equivalent access to the host — it can mount arbitrary host paths into new containers, read any file on the host filesystem, spawn privileged containers, and escape the isolation that clawker otherwise provides. This effectively negates container isolation as a security boundary.Docker-outside-of-Docker (DooD) was chosen over Docker-in-Docker (DinD) for performance and reliability — DinD requires a nested daemon, consumes significantly more resources, and introduces complex storage driver issues. However, alternative approaches that provide Docker capabilities without full socket access are being evaluated for future releases.If you enable this setting, treat the session as supervised. Do not leave an agent running unattended with socket access. Review what containers and volumes the agent creates. Disable security.docker_socket when Docker access is not actively needed.
clawker’s own resource jailing (pkg/whail) is a UX feature for the user, not a security boundary for the agent. It prevents you from accidentally running clawker volume prune and deleting non-clawker volumes. But the agent inside the container uses the real Docker CLI, not clawker — so the jailing doesn’t apply. Only enable the Docker socket if your workflow genuinely requires container-driven development (e.g., building and running containers as part of your CI or dev workflow). Otherwise, leave it off.

Privileged Mode

Clawker does not run containers in privileged mode by default. The --privileged flag is available on clawker container create and clawker container exec for users who explicitly need it, but it is off unless you ask for it.
Running containers with --privileged grants elevated permissions and can expose the host system to security risks. Privileged mode broadly relaxes confinement — seccomp filtering and AppArmor profiles are typically disabled, capabilities like CAP_SYS_ADMIN are added, and device access controls are opened up. While the container still runs in its own namespaces, these permissions allow it to effectively bypass isolation (for example by mounting host filesystems) and interact with the host kernel much like a root process on the host. Use this option only when absolutely necessary and in trusted environments.Clawker’s security controls (unprivileged user, nosuid mounts, seccomp, capability dropping) are effectively neutralized in privileged mode. If you pass --privileged, you are accepting full responsibility for what the agent does.

Bypass Discipline

The bypass exists to avoid firewall rule management fatigue. Sometimes the agent just needs to do some research or install a package and you don’t want to add permanent rules for a one-off domain. That’s what bypass is for — short, supervised windows of unrestricted access. Use small time windows (e.g., clawker firewall bypass 30s --agent dev). Pay attention while it’s active. If you notice anything suspicious, immediately close the bypass with clawker firewall bypass --stop --agent <agent-name>. Bypass is scoped to a specific agent — it only toggles the egress restrictions for that one container. The firewall stack itself is not turned off, and all other agents continue to have their traffic routed through it normally. This limits exposure to a single container rather than your entire fleet. That said, the bypassed container has fully unrestricted network access for the duration, so don’t leave long bypasses running unattended.

Workspace Scope

Be intentional about what you bind-mount:
  • Don’t mount directories containing .env files, private keys, or credentials the agent doesn’t need.
  • Use .clawkerignore to mask sensitive directories.
  • Use snapshot mode for experimental or high-risk agent tasks where you don’t want any changes reaching the host.

Base Image Trust

Custom build instructions (build.instructions in your project config) run during image build. Injected root_run commands execute as root. Review what you’re adding — package sources, custom scripts, and copied files are part of your supply chain.

Resource Limits

Clawker containers are throwaway devcontainers, not production workloads. Docker handles OOM kills natively, but you should configure your Docker engine’s default resource limits to prevent a runaway agent from starving the host. Use --memory and --cpus flags on container creation for per-agent limits.