Status: ROADMAP — captured 2026-04-25 from a discussion of Kloak’s eBPF kernel-level interception approach.
Kloak (Kubernetes eBPF HTTPS interceptor) achieves a strong property: the application never holds real secrets. The app holds opaque placeholder tokens; an eBPF program in the kernel TLS path swaps placeholders for real credentials at the moment of network send. If the app process is compromised and its memory is dumped, the attacker gets placeholders, not credentials.
We can’t trivially port their mechanism — eBPF is Linux-only, requires root + recent kernels, and TLS interception specifically requires uprobes into userspace TLS libraries. Calciforge runs on macOS as a first-class target; we’d be cutting that off.
The same property — “agent never holds real secret” — can be achieved with our existing HTTP-proxy architecture by inverting the current flow:
Authorization: Bearer Property: agent never sees the real value, BUT must know about the substitution syntax. Off-the-shelf agents that don’t know about Calciforge can’t use this — they hardcode env-var reads.
OPENAI_API_KEY=cfg_OPENAI_KEY_a1b2c3d4e5f6... (per-agent random)Authorization: Bearer … header carrying the placeholder valueProperty: agent never sees the real value AND doesn’t need to know about Calciforge. Works with any off-the-shelf agent that reads credentials from env vars.
Status as of 2026-05-12: the security-proxy-local primitives are merged, but live placeholder substitution is intentionally not enabled yet.
Implemented pieces:
cfg_<NAME>_<32-hex>.PlaceholderMap that resolves agent_id + token to an
authoritative secret name.SecurityProxy placeholder-name resolution helper that
scans request text, resolves token -> secret name, and applies the
same policy gate as explicit `` references.Not yet wired:
The next safe implementation slice is Calciforge-side lifecycle wiring: decide which supervised agent runtime owns placeholder creation, where generated values are injected, and where single-token or whole-agent retirement is called. That delivery surface may be an env var for CLI agents, a wrapper-generated config file, or a managed credentials folder for agents that already expect plaintext files. Live substitution should remain disabled until that owner can deterministically register and retire tokens.
That boundary is explicit: calciforge currently owns agent config and
adapter construction, while security-proxy owns the in-memory
placeholder registry. AgentConfig.env is cloned into concrete
subprocess adapters at adapter construction time, and installer-managed
wrappers separately export CALCIFORGE_AGENT_ID for central secret
helper calls. Do not hide placeholder generation inside an adapter
constructor by making adapters reach into SecurityProxy; that would
make lifecycle ownership and retirement ambiguous. The next
implementation should either move the placeholder lifecycle API into a
shared crate used by both sides, or add an explicit Calciforge-owned
registration channel/client before adapter env maps are rewritten.
Per-agent state in security-proxy:
pub struct PlaceholderMap {
/// agent_id → placeholder token → real secret name
/// e.g. "claude-research" → "cfg_OPENAI_KEY_a1b2..." → "OPENAI_API_KEY"
by_agent: HashMap<String, HashMap<String, String>>,
}
When Calciforge starts an agent (today: the channel router does this indirectly via the openclaw adapter; tomorrow: explicit “spawn under supervision” entry point):
When security-proxy sees an outbound request, it scans body + headers
for placeholder shapes (regex on the cfg_*_* prefix) and swaps
through PlaceholderMap before forwarding. Same code path as
`` substitution — just a different recognizer.
Important invariant: the placeholder path must never trust the
embedded <NAME> hint in cfg_<NAME>_<random>. It must resolve the
full opaque token through the per-agent map, apply the same
per-agent/user/channel secret access policy and destination allowlist
as explicit `` substitution, and only then load the real
secret value.
| Property | True eBPF | Placeholder injection |
|---|---|---|
| Agent never sees real secret | ✅ | ✅ |
| Works without agent’s awareness of Calciforge | ✅ | ✅ |
| Kernel-enforced (agent can’t bypass) | ✅ | ❌ (agent can bypass cooperative proxy env unless paired with host/container egress controls) |
| Linux only | yes | no — cross-platform |
| Requires root | yes (CAP_BPF) | no |
| Requires recent kernel | yes (5.x+) | no |
| Engineering cost | months | ~1 week |
| Debuggability | brutal | normal HTTP-proxy logs |
| Compatible with our existing substitution engine | rewrite | direct extension |
Things both approaches catch:
Things only true eBPF catches:
Things neither catches:
cfg_<NAME>_<32-hex> — 36 chars + name length.OPENAI_API_KEY get different placeholders pointing to the same
real value. Keeps per-agent isolation.AgentConfig.env and supervised process construction. Security-proxy
must own the authoritative token registry and value-substitution
policy. A shared lifecycle API or explicit registration client should
connect those two responsibilities.~1 week for a working prototype:
Compared to the months that a true eBPF implementation would take (plus the ongoing Linux-only constraint), the cost-benefit strongly favors placeholder injection unless someone shows up needing kernel- enforced isolation specifically.