odek's 21st-Century Security Posture

Depth-per-Dependency as a Defensive Architecture

odek's 21st-Century Security Posture ~3K words

odek's 21st-Century Security Posture

Depth-per-Dependency as a Defensive Architecture

odek is a minimal Go agent runtime that executes shell commands, reads and writes files, fetches URLs, and spawns sub-agents. That capability is the product — and it is also the attack surface. odek's answer is unusual among AI agents: rather than layering a permission system over a large dependency tree, it compresses the supply chain to five modules and spends the saved complexity budget on an adversarially-tested, layered defense stack.

This essay examines that architecture as implemented in the odek repository (August 2026 tree; internal audit register at b14771d [1]), then compares it to Claude Code and OpenAI Codex using each vendor's official security documentation [4][5][6][9][10][11].


The Thesis: Surface Area Is a Security Property

Most agent frameworks treat security as a bolt-on: a permission modal here, an allowlist there, wrapped around hundreds of transitive packages. odek inverts the problem.

Its dependency footprint is five modulesgo-mcp, go-vector, and three golang.org/x/ packages (net, term, sys). go.sum contains ten entries across five unique modules [3]. The result is a ~11 MB static binary (release artifacts measure 10.6–11.6 MB across the four supported platforms [3]) with instant startup — and, more importantly, a supply chain small enough that one human can audit every line of third-party code the binary will ever load.

This is not aesthetic minimalism. Every dependency is a trusted execution domain: a package you cannot audit is a package that executes on your behalf with your credentials. Claude Code ships as a native binary behind thin installers (npm install -g @anthropic-ai/claude-code, Homebrew) [17] — but the binary itself is closed source, so its supply chain is taken on trust rather than verified. Codex CLI is open-source Rust — a strong memory-safety story — but its codex-rs/Cargo.lock resolves 1,359 locked crates [13]. odek's five-module closure is under 0.4% of that number, and every line of it is open to inspection.


The Threat Model — Explicit and Honest

odek's security documentation states, in writing, what it does and does not defend against [1]:

This candor is itself a security control. Most tools imply protection they cannot deliver; odek documents the boundary so operators deploy with accurate expectations. It is also explicitly a single-operator design.


The Layered Defense Stack

Seven layers stand between an injected payload and the operator's machine — from ingest, to execution, to what leaves the process:

flowchart LR
    A["Injected payload
(page · file · MCP · transcript)"] --> B["Untrusted-content boundary
+ injection guard"] B --> C["Danger classifier
normalize · decompose · fails closed"] C --> D["Approval gate
friction-throttled"] D --> E["Sandbox
no network · zero caps"] E --> F["Redaction + audit
scrubbed output · hashed args"] F --> G["Host"]

Layer 0 — Minimal supply chain

Five modules, a static ~11 MB binary, nothing else. The foundation every other layer sits on.

Layer 1 — Sandboxed execution (`internal/sandbox`)

odek serve enables Docker sandboxing by default; odek run keeps it opt-in but warns loudly when unsandboxed. It is a genuine isolation boundary [2]:

Layer 2 — The danger classifier (`internal/danger`, 3,211 LOC)

The heart of the posture. Shell commands are not regex-matched; they are parsed adversarially, because the threat model assumes a prompt-injected agent is actively trying to make a dangerous command read as harmless [1]:

  1. Normalization — the command is rewritten so token analysis can see through shell tricks before classification: $'\x72\x6d' ANSI-C escapes, $IFS word-splitting (rm$IFS-rf$IFS/), brace expansion, command substitution, command/exec wrappers, backslash escapes, and absolute paths.
  2. Structural decomposition — commands are split on ;/&&/||, then into pipe stages, and every stage is classified — not just the head — so true | dd of=/dev/sda is caught. Pipelines into xargs have their upstream literal payload composed onto the inner command.
  3. Nine risk classes (safe, local_write, system_write, destructive, network_egress, code_execution, install, blocked, unknown) mapped to allow/prompt/deny.

The defining property: the gate fails closed. An unrecognized verb classifies as unknown and is denied by default. A novel obfuscation that dodges every known-dangerous check cannot run.

Layer 3 — Approval gate with fatigue resistance

Dangerous commands trigger approval, but FrictionThreshold/FrictionWindow (3 prompts / 60s by default) throttle approval streams — treating approval fatigue as a first-class attack, not a UX annoyance [1].

Layer 4 — Prompt-injection guard (`internal/guard`)

A pluggable Guard interface with two backends: a zero-dependency local rule-based scan, and a piguard semantic sidecar (HTTP or Unix socket) as a second opinion [1]. The guard config is operator-only and rejected from project-level ./odek.json, so a malicious repo cannot disable the scan or redirect system-prompt content to an attacker endpoint.

Layer 5 — Secret redaction (`internal/redact`)

A lexical redaction layer sanitizes tool output before it reaches the transcript, session file, provider logs, or a Telegram chat [1]. It precomputes common encodings (base64, hex, URL, reversed) so echo $API_KEY | base64 does not leak; it matches known values registered from the environment plus format patterns; and it handles /proc/self/environ NUL-delimited dumps. The docs are equally honest about what redaction cannot do — arbitrary transformation and side-channel exfiltration are deferred to egress controls and approval gating.

Layer 6 — Untrusted-content boundary + SSRF

Every tool sourcing from outside the trust boundary wraps its result in a per-call nonce'd boundary tag, so an attacker cannot embed a literal close-tag to escape the wrapper — and the model always knows which content is untrusted. Network tools re-classify every redirect hop, and a dial guard blocks internal/metadata IPs (169.254.169.254), RFC 6598 CGNAT, and RFC 2544 ranges — closing SSRF against cloud metadata and overlay networks [1].

Layer 7 — Durability and hygiene

Atomic writes (O_CREATE|O_EXCL + fsync + rename), 0600/0700 state permissions, event-stream redaction (tool arguments logged only as SHA-256 digests), resource bounds everywhere (1 MiB shell output, 10 MiB reads), and SHA-256-verified upgrades [1].

The verification story

None of the above is aspirational — the defense stack is regression-tested. The six security-relevant packages (danger, guard, redact, sandbox, fsatomic, pathutil) carry 298 test functions, including dedicated classifier-bypass suites (classifier_bypass_test.go, audit_regressions_test.go, hardening_test.go) and a whitebox suite pinning normalization behaviour [2]. The repository documents the default suite as clean under go test -race ./..., with the Docker/subprocess E2E set behind an opt-in flag.


The Competitive Landscape — From Official Documentation

Claude Code *(Anthropic)*

OpenAI Codex


Comparison

Axis odek Claude Code Codex
Runtime / supply chain Go, static 10.6–11.6 MB, 5 modules, open source Native binary via npm/Homebrew; closed source Rust, open source, 1,359 locked crates [13]
Sandbox mechanism Docker container (default-on in serve) OS-native: Seatbelt / bubblewrap + socat proxy (optional seccomp) OS-native: Seatbelt / bubblewrap / Windows sandbox
Network default Off (none) Manual-mode approvals; sandbox isolates Off
Command classification Deterministic, token-based, fails closed (unknown → deny) Model-based classifier (auto mode) + read-only allowlist Prefix rules (Starlark) + sandbox boundary
Obfuscation resistance Normalization layers ($IFS, ANSI-C, xargs composition) Model judgment (not deterministic) Prefix matching (not obfuscation-aware)
Approval-fatigue model Explicit — friction throttling Allowlisting per-scope Sandbox reduces prompts; auto-review mode
Prompt-injection guard Local scan + optional semantic sidecar Context analysis + isolated fetch windows Model-level + approval/sandbox
Secret redaction First-class layer (encodings, known-values, proc-environ) Not a documented layer Not a documented layer (OTel user_prompt redacted)
SSRF hardening Redirect re-classification + internal/metadata IP block Partial (network approval) Domain rules + Unix-socket allowlist
Threat model Published, with named out-of-scope Implicit Implicit (white paper)
Adversarial test rigor 298 test functions across 6 security packages, incl. bypass-regression suites [2] Not published Not published
Compliance / governance SOC 2, ISO 27001, bug bounty White paper, OTel audit, managed config

A Convergent Architecture — and What Still Differentiates

The most significant finding from the official documentation is convergence: all three tools now ship the same two-layer mental model — a technical sandbox boundary (what the agent can do) plus an approval/classification layer (when it must stop and ask). Claude Code's "sandbox + permission modes" and Codex's "sandbox mode + approval policy" are, architecturally, the same idea. The difference is where the intelligence sits:

Where odek leads

  1. Depth-per-dependency. Five modules versus Codex's 1,359 locked crates is a ~270× difference in third-party code; versus Claude Code, the differentiator is auditability — an open, enumerable closure against a closed binary.
  2. Fails-closed determinism. An unrecognized command is denied. Codex's prefix rules only match what you enumerate; Claude Code's auto-mode classifier is a model — fallible, not verifiable. odek's classifier is deterministic, testable, and ships bypass-regression suites.
  3. Adversarial shell normalization. $IFS, ANSI-C escapes, and xargs payload composition are the specific evasions a prompt-injected agent will use — and odek is the only one of the three that documents a dedicated normalization layer for them (Claude Code's Bash(...) rules and Codex's prefix_rule are literal prefix matches).
  4. Redaction as a first-class control. Neither competitor documents an equivalent tool-output secret-scrubbing layer.
  5. Published, honest threat model. odek's docs enumerate out-of-scope threats by name; neither competitor publishes an equivalent scope statement in its public docs.

Where odek trails

  1. Docker dependency. The strongest isolation layer needs Docker. Claude Code and Codex sandbox via OS primitives (Seatbelt/bubblewrap) with no daemon — strictly more portable.
  2. No model-level resistance. Claude Code and Codex benefit from frontier-lab instruction-honing against injection; odek's defense is entirely wrapper-level.
  3. No compliance/enterprise story. Claude Code has SOC 2/ISO 27001 and managed org policies; Codex has requirements.toml, OTel audit events, and a security white paper. odek is a single-operator tool.
  4. No second-opinion by default. The semantic piguard sidecar is opt-in; the local scan is rule-based only.

Honest Limitations


Conclusion

odek's posture is best summarized by its thesis: when the dependency tree is small enough to audit, the defense budget can be spent on the actual threat — an adversarial model wielding your shell. Its classifier fails closed, its sandbox is default-on and network-off, its redaction layer closes the tool-output exfiltration path, and its documentation is honest about what none of it can stop.

The comparison is not "odek is safer than Claude Code or Codex." It is that all three have converged on a sandbox-plus-approval architecture, and they differ on where the intelligence sits. Claude Code trusts a second model; Codex trusts a rules engine and OS sandbox; odek trusts a deterministic, de-obfuscating parser and a five-module supply chain. For a single operator who wants the smallest possible surface between an LLM and their machine — and the ability to read every line of code that runs with their credentials — that is a defensible, 21st-century answer.


Kyberneees, August 2026

References

[1] odek repository — https://github.com/BackendStack21/odekdocs/SECURITY.md, docs/SANDBOXING.md, docs/REDACTION_HARDENING.md, sec_findings.md.

[2] odek source — internal/danger/classifier.go, internal/danger/approver.go, internal/guard, internal/redact, internal/sandbox, internal/fsatomic.

[3] odek module graph and release artifacts — go.mod/go.sum (5 modules total: 4 direct + golang.org/x/sys; the entire transitive closure) and GitHub release binaries (10.6–11.6 MB across the four supported platforms).

[4] Anthropic, Securityhttps://code.claude.com/docs/en/security

[5] Anthropic, Configure the sandboxed Bash toolhttps://code.claude.com/docs/en/sandboxing

[6] Anthropic, Configure permissionshttps://code.claude.com/docs/en/permissions

[7] Anthropic Trust Center (SOC 2 Type 2, ISO 27001) — https://trust.anthropic.com

[8] Anthropic, Security Policy (HackerOne) — https://github.com/anthropics/claude-code/blob/main/SECURITY.md

[9] OpenAI, Agent approvals & securityhttps://learn.chatgpt.com/docs/agent-approvals-security

[10] OpenAI, Sandboxhttps://learn.chatgpt.com/docs/sandboxing

[11] OpenAI, Permission modeshttps://learn.chatgpt.com/docs/permission-modes

[12] OpenAI, Rules (exec policy) — https://learn.chatgpt.com/docs/agent-configuration/rules

[13] OpenAI, Codex CLI repository — https://github.com/openai/codex (codex-rs/Cargo.lock: 1,359 packages).

[14] OpenAI, Codex security white paper — https://trust.openai.com

[15] OWASP, Top 10 for LLM Applications — LLM01: Prompt Injection — https://genai.owasp.org

[16] NIST, Artificial Intelligence Risk Management Framework (AI RMF 1.0)https://www.nist.gov/itl/ai-risk-management-framework

[17] Anthropic, Set up Claude Code (install methods) — https://code.claude.com/docs/en/setup