{"id":50218486,"url":"https://github.com/reoring/botbox","last_synced_at":"2026-05-26T10:34:15.628Z","repository":{"id":337559478,"uuid":"1154170681","full_name":"reoring/botbox","owner":"reoring","description":"Kubernetes sidecar that sandboxes container egress. Deny-by-default allowlist + automatic credential injection via iptables — no proxy config needed. Built for confining AI agents.","archived":false,"fork":false,"pushed_at":"2026-02-10T05:54:20.000Z","size":713,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-10T10:40:33.873Z","etag":null,"topics":["ai-agents","clawdbot","kubernetes","moltbot","openclaw","sandbox","security"],"latest_commit_sha":null,"homepage":"https://github.com/reoring/botbox","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/reoring.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"docs/security.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-10T04:51:57.000Z","updated_at":"2026-02-10T09:27:28.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/reoring/botbox","commit_stats":null,"previous_names":["reoring/botbox"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/reoring/botbox","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reoring%2Fbotbox","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reoring%2Fbotbox/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reoring%2Fbotbox/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reoring%2Fbotbox/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/reoring","download_url":"https://codeload.github.com/reoring/botbox/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reoring%2Fbotbox/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33517115,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T03:12:49.672Z","status":"ssl_error","status_checked_at":"2026-05-26T03:12:47.976Z","response_time":63,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai-agents","clawdbot","kubernetes","moltbot","openclaw","sandbox","security"],"created_at":"2026-05-26T10:34:13.656Z","updated_at":"2026-05-26T10:34:15.607Z","avatar_url":"https://github.com/reoring.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# BotBox\n\n[![CI](https://github.com/reoring/botbox/actions/workflows/ci.yml/badge.svg)](https://github.com/reoring/botbox/actions/workflows/ci.yml)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)\n[![Rust](https://img.shields.io/badge/Rust-1.93.0-orange.svg)](https://www.rust-lang.org/)\n\nEnglish | [日本語](README.ja.md)\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/botbox.png\" alt=\"BotBox\" width=\"600\"\u003e\n\u003c/p\u003e\n\n**Sandbox any container's network — especially AI agents.**\n\nBotBox is a Kubernetes sidecar proxy that sits between your container and the internet. It intercepts all outbound traffic via iptables, enforces a deny-by-default allowlist, and injects API keys at the network boundary — so the container itself never holds credentials and can only reach hosts you explicitly permit.\n\n### AI Agent Containment\n\nRunning an autonomous AI agent (LLM-based coding agent, tool-use agent, etc.) in a container? BotBox gives you a hard network boundary:\n\n- **The agent can only reach hosts you allow.** Deny-by-default policy blocks all other egress — no data exfiltration, no unauthorized API calls.\n- **The agent never sees real API keys.** Credentials are stored in Kubernetes Secrets and injected by BotBox at the network layer. Even if the agent dumps its own environment or memory, there are no keys to leak.\n- **Zero app changes required.** iptables transparent redirect means the agent doesn't need proxy settings — it just makes normal HTTP requests and BotBox handles the rest.\n- **Auditable.** Every request is logged with structured tracing. You can see exactly what your agent tried to reach and whether it was allowed or denied.\n\n```mermaid\nflowchart LR\n    subgraph Pod\n        Agent[\"🤖 AI Agent\u003cbr/\u003e\u003ci\u003eno credentials\u003c/i\u003e\"]\n        IPT[/\"iptables\u003cbr/\u003etransparent\u003cbr/\u003eredirect\"/]\n        BotBox[\"🔒 BotBox\u003cbr/\u003e\u003ci\u003esidecar\u003c/i\u003e\"]\n    end\n\n    Agent -- \"curl http://api.openai.com\" --\u003e IPT\n    IPT -- \":80 → :8080\" --\u003e BotBox\n\n    BotBox -- \"✅ Allowed + TLS + Key injected\" --\u003e API[\"api.openai.com\"]\n    BotBox -. \"❌ Denied → 403\" .-\u003e Agent\n\n    style Agent fill:#fef3c7,stroke:#d97706\n    style BotBox fill:#dbeafe,stroke:#2563eb\n    style API fill:#d1fae5,stroke:#059669\n```\n\nThis makes BotBox a natural fit for any scenario where you need to **run untrusted or semi-trusted code** with controlled, auditable network access.\n\n## How it Works\n\n### Modes of Operation\n\nBotBox supports two modes:\n\n1. **HTTP-only (default)** -- Intercepts plaintext HTTP on port 80, rewrites headers, and originates TLS to upstream. App containers make `http://` requests and BotBox upgrades them to HTTPS.\n2. **HTTPS Interception** -- Additionally intercepts outbound HTTPS on port 443 via a TLS-terminating listener on port 8443. BotBox dynamically issues short-lived leaf certificates signed by a local CA, decrypts the traffic, applies the same allowlist and header-rewrite pipeline, then re-encrypts to the upstream. This allows credential injection into HTTPS requests without requiring the app to use plaintext HTTP.\n\n### Request Processing\n\n```mermaid\nflowchart LR\n    A[\"HTTP request\"] --\u003e B{\"Allowlist\"}\n    B -- \"deny\" --\u003e C[\"403\"]\n    B -- \"allow\" --\u003e D[\"Rewrite headers\\n+ inject secrets\"] --\u003e E[\"TLS → upstream\"]\n\n    style C fill:#fee2e2,stroke:#dc2626\n    style E fill:#d1fae5,stroke:#059669\n```\n\nSee [Architecture](docs/architecture.md) for the full request processing pipeline.\n\n### iptables Network Rules\n\n```mermaid\nflowchart TD\n    OUT[\"Outbound packet\u003cbr/\u003e\u003ci\u003eOUTPUT chain\u003c/i\u003e\"] --\u003e FIL{\"EGRESS_FILTER\"}\n\n    FIL -- \"loopback\" --\u003e PASS1[\"✅ RETURN\"]\n    FIL -- \"UID 1337\u003cbr/\u003e\u003ci\u003eBotBox itself\u003c/i\u003e\" --\u003e PASS2[\"✅ RETURN\"]\n    FIL -- \"DNS (53)\" --\u003e PASS3[\"✅ RETURN\"]\n    FIL -- \"other TCP/UDP\" --\u003e DROP[\"🚫 DROP\"]\n\n    OUT --\u003e NAT{\"EGRESS_REDIRECT\u003cbr/\u003e\u003ci\u003eNAT\u003c/i\u003e\"}\n    NAT -- \"loopback\" --\u003e SKIP1[\"RETURN\"]\n    NAT -- \"UID 1337\" --\u003e SKIP2[\"RETURN\"]\n    NAT -- \"TCP :80\" --\u003e REDIR[\":80 → :8080\u003cbr/\u003e\u003ci\u003eREDIRECT to BotBox\u003c/i\u003e\"]\n    NAT -- \"TCP :443\" --\u003e REDIR443[\":443 → :8443\u003cbr/\u003e\u003ci\u003eREDIRECT to HTTPS\u003cbr/\u003einterception\u003c/i\u003e\"]\n\n    style DROP fill:#fee2e2,stroke:#dc2626\n    style REDIR fill:#dbeafe,stroke:#2563eb\n    style REDIR443 fill:#dbeafe,stroke:#2563eb\n```\n\n## HTTPS Interception Mode\n\nWhen enabled, BotBox intercepts outbound HTTPS traffic by terminating TLS at the sidecar and re-encrypting to the upstream. This lets BotBox inspect and rewrite headers inside HTTPS requests -- the same allowlist, header-rewrite, and credential-injection pipeline applies.\n\n### How It Works\n\n1. iptables redirects outbound TCP port 443 to BotBox's HTTPS interception listener on port 8443.\n2. BotBox terminates TLS using a dynamically issued leaf certificate (signed by a local CA).\n3. The decrypted HTTP request passes through the standard proxy pipeline (allowlist check, header rewrite, secret injection).\n4. BotBox re-encrypts and forwards the request to the upstream over TLS.\n\nThe app container sees a valid TLS connection (signed by the local CA) and does not need any proxy configuration.\n\n### Configuration\n\nAdd an `https_interception` block to your config:\n\n```yaml\nhttps_interception:\n  enabled: true\n  listen_addr: \"127.0.0.1\"\n  listen_port: 8443\n  ca_cert_path: \"/etc/botbox/https_interception/ca.crt\"\n  ca_key_path: \"/etc/botbox/https_interception/ca.key\"\n  enforce_sni_host_match: true       # default: true -- reject requests where Host header != SNI\n  deny_handshake_on_disallowed_sni: false  # default: false -- when true, refuse TLS handshake for non-allowlisted hosts\n  cert_ttl_seconds: 86400            # default: 86400 (24h) -- leaf cert validity period\n  cert_cache_size: 1024              # default: 1024 -- LRU cache capacity\n  cert_cache_ttl_seconds: 3600       # default: 3600 (1h) -- cache entry TTL\n  handshake_timeout_ms: 5000         # default: 5000 -- TLS handshake timeout\n```\n\nEnvironment variable overrides:\n\n| Variable | Description |\n|---|---|\n| `BOTBOX_ENABLE_HTTPS_INTERCEPTION` | Set to `1` in the iptables init container to add the port-443 NAT redirect |\n| `BOTBOX_HTTPS_INTERCEPTION_PORT` | Override the HTTPS interception listen port (default: 8443) |\n\n\u003e **Note:** HTTPS interception requires **both** the config file setting (`https_interception.enabled: true`) and the iptables environment variable (`BOTBOX_ENABLE_HTTPS_INTERCEPTION=1`). The config tells BotBox to start the TLS listener; the environment variable tells the init container to install the NAT redirect rule.\n\n\u003e **Note:** When `BOTBOX_ENABLE_HTTPS_INTERCEPTION=1`, keep `BOTBOX_REDIRECT_FROM_PORT=80` (the default). Setting `BOTBOX_REDIRECT_FROM_PORT=443` conflicts with the HTTPS interception redirect; the init script fails fast to avoid silently routing HTTPS into the plain HTTP listener.\n\n\u003e **Note:** `BOTBOX_ENABLE_IPV6` is a **required** environment variable for the iptables init container (no default). Set to `1` for dual-stack environments (mirrors all rules via ip6tables) or `0` for IPv4-only. The script exits with an error if this variable is not set.\n\n### iptables Rules for HTTPS Interception\n\nThe init container must add a NAT redirect for port 443 in addition to the existing port 80 rule:\n\n```bash\niptables -t nat -A EGRESS_REDIRECT -p tcp --dport 443 -j REDIRECT --to-port 8443\n```\n\n### App-side CA Trust\n\nThe app container must trust the BotBox CA certificate. Mount the CA cert (NOT the private key) into the app container and configure the runtime:\n\n| Runtime / Library | Environment Variable or Flag |\n|---|---|\n| curl / OpenSSL | `CURL_CA_BUNDLE=/etc/botbox/https_interception/ca.crt` or `SSL_CERT_FILE=/etc/botbox/https_interception/ca.crt` |\n| Node.js | `NODE_EXTRA_CA_CERTS=/etc/botbox/https_interception/ca.crt` |\n| Python requests | `REQUESTS_CA_BUNDLE=/etc/botbox/https_interception/ca.crt` |\n| JVM (Java, Kotlin) | `-Djavax.net.ssl.trustStore=/path/to/truststore.jks` (import the CA cert into a JKS truststore) |\n| Go (net/http) | `SSL_CERT_FILE=/etc/botbox/https_interception/ca.crt` |\n\n**Security note:** The CA **private key** must NOT be mounted into app containers. Only the CA certificate (public) should be shared. The private key must be in a separate volume accessible only to the BotBox sidecar.\n\n### Kubernetes gotchas (from the example manifests)\n\n- Loopback-only listeners vs probes: BotBox's metrics server binds to `127.0.0.1`, and `https_interception.listen_addr` is required to be loopback. Kubernetes `httpGet` probes hit the Pod IP, so they will time out if you point them at `:9090/healthz` (or `:8443`) while those listeners are bound to loopback.\n- Prefer an `exec` probe in any container that has a HTTP client (your app container, or a tiny curl sidecar) and probe `http://127.0.0.1:9090/healthz` from inside the Pod network namespace. The default BotBox image is distroless, so it does not include `/bin/sh` or `curl`.\n\nExample `exec` readiness probe:\n\n```yaml\nreadinessProbe:\n  exec:\n    command:\n      - /bin/sh\n      - -c\n      - curl -sf --connect-timeout 1 --max-time 1 http://127.0.0.1:9090/healthz \u003e/dev/null\n  initialDelaySeconds: 1\n  periodSeconds: 2\n  timeoutSeconds: 1\n```\n\n- Ephemeral CA for dev: the example generates a throwaway CA keypair in an initContainer into an `emptyDir`. This is convenient for development, but for production you probably want a stable CA stored in a Kubernetes Secret.\n\n## Quickstart\n\n### Prerequisites\n\n- Docker\n- [kind](https://kind.sigs.k8s.io/)\n- kubectl\n\n### 1. Build and load the images\n\n```bash\ndocker build -t botbox:test .\ndocker build --target iptables-init -t botbox-iptables-init:test .\nkind load docker-image botbox:test botbox-iptables-init:test\n```\n\n### 2. Write your egress policy\n\n```yaml\n# config.yaml\nallow_non_loopback: false  # keep false unless intentionally exposing outside the pod\negress_policy:\n  default_action: deny\n  rules:\n    - host: api.openai.com\n      action: allow\n      header_rewrites:\n        - name: Authorization\n          value: \"Bearer {value}\"\n          secret_ref: openai-api-key   # reads from K8s Secret\n```\n\n### 3. Add the sidecar to your pod\n\n```yaml\ninitContainers:\n  - name: iptables-init          # installs the recommended iptables NAT+filter rules\n    image: botbox-iptables-init:test\n    env:\n      - name: BOTBOX_ENABLE_IPV6\n        value: \"1\"              # required — set to \"0\" if ip6tables or ip6table_nat is unavailable\n    securityContext:\n      capabilities: { add: [NET_ADMIN] }\n      runAsUser: 0\n      runAsNonRoot: false\n\n  - name: botbox                  # runs for the pod's lifetime\n    image: botbox:test\n    restartPolicy: Always\n    args: [\"--config\", \"/etc/botbox/config.yaml\"]\n    securityContext:\n      runAsUser: 1337\n      runAsNonRoot: true\n    # mount your ConfigMap and Secret here\n\ncontainers:\n  - name: app                     # your application — no proxy config needed\n    image: your-app:latest\n    securityContext:\n      runAsNonRoot: true\n      runAsUser: 1000             # must NOT be 1337 (BotBox UID) or iptables owner-match can be bypassed\n```\n\nOr try the ready-to-apply Kubernetes example (HTTPS interception enabled):\n\n```bash\nkubectl apply -k examples/https_interception\nkubectl -n botbox-https-interception rollout status deploy/botbox-https-interception-demo\nkubectl -n botbox-https-interception exec -it deploy/botbox-https-interception-demo -c client -- sh\n```\n\n### 4. Run acceptance tests on kind (automated)\n\n```bash\ntests/e2e/run-kind-acceptance.sh\n```\n\n### 5. Run individual E2E tests (optional)\n\n```bash\ntests/e2e/run-egress-test.sh\ntests/e2e/run-https-interception-test.sh\n```\n\n### 6. Run unit tests\n\n```bash\ncargo test\n```\n\n## Why\n\n| Problem | How BotBox solves it |\n|---|---|\n| API keys leaked in app env vars | Keys live only in K8s Secrets, injected at the network boundary |\n| Apps must configure HTTP_PROXY | iptables makes interception transparent — zero app changes |\n| Uncontrolled outbound traffic | Deny-by-default allowlist; only approved hosts are reachable |\n| Key rotation requires restarts | Secrets directory is watched with inotify; hot-reload, no downtime |\n\n## Documentation\n\n- [Architecture](docs/architecture.md) — module structure, request flow, iptables rules, configuration reference\n- [Security](docs/security.md) — threat model, controls, hardening checklist, residual risks\n- [BotBox vs Deno Sandbox](docs/vs-deno-sandbox.md) — `allowNet`/`secrets` comparison, allowlisted-upstream risk analysis\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Freoring%2Fbotbox","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Freoring%2Fbotbox","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Freoring%2Fbotbox/lists"}