“Bring your own key” looks like a settings feature. For an AI coding agent, it is also a security boundary: a privileged workload will send repository context, prompts, and credentials toward a network destination selected by configuration.
That boundary deserves more than a successful GET /models request.
I reviewed MonkeyCode, an open-source AI development platform, at commit c58bcd4. Its source provides a useful concrete case because users can configure model providers while task runtimes receive proxy credentials.
This is a source review, not a penetration test. In particular, I am not claiming encryption, rotation, or revocation behavior that the reviewed files do not establish.
Map the two credential planes
The reviewed model API-key schema and model repository separate a configured provider credential from a runtime API key.
The task path then calls CreateRuntimeAPIKey and gives the runtime a proxy base URL plus that runtime token. In the reviewed repository logic, a token is associated with a user, model, and VM; a token for the same user and VM can be reused and rebound to a model.
That yields two distinct questions:
| Plane | Secret holder | Security question |
|---|---|---|
| Provider plane | Control service | Can this credential call only the intended provider, models, and operations? |
| Runtime plane | Agent VM | Is this delegated token narrowly bound, short-lived, observable, and invalid after its task boundary ends? |
A proxy reduces direct provider-key exposure inside the VM. It does not automatically settle endpoint trust, server-side storage, token lifetime, replay, or revocation.
Treat the base URL as code execution input
A configurable model base URL controls where sensitive payloads leave the platform. Audit it like a webhook destination or package registry:
- Require HTTPS and perform normal certificate validation.
- Reject URL-embedded credentials.
- Resolve and authorize the destination, including redirect targets; protect link-local, loopback, and private metadata ranges unless explicitly required.
- Allow-list expected hosts and ports for managed deployments.
- Bind the provider credential to inference-only permissions where the provider supports scopes.
- Log destination identity, model ID, caller, VM, and decision result without logging prompts or secrets.
TLS answers “is this encrypted to the named peer?” It does not answer “should this peer receive the repository?” An allow-list or administrator approval supplies that missing policy decision.
Make the policy executable
Here is a small policy document from the companion files:
{
"endpoint": "https://llm-gateway.example/v1",
"allowed_hosts": ["llm-gateway.example"],
"require_https": true,
"forbid_url_credentials": true,
"key_scope": "model-inference-only",
"runtime_credential": {
"audience": "llm-proxy",
"bound_to": ["user", "model", "vm"],
"max_ttl_seconds": 3600
},
"egress": { "allowed_ports": [443], "follow_redirects": false }
}
The included zero-dependency checker rejects HTTP, URL credentials, unknown hosts, unrestricted key scope, missing bindings, excessive TTL, and redirects:
node check-policy.mjs byok-policy.json
node test-policy.mjs
Expected output:
PASS BYOK endpoint policy
PASS policy accepts the safe fixture and rejects five unsafe properties
This is a configuration gate, not a network scanner. Production enforcement must also validate DNS results at connection time, prevent redirect bypass, use a trusted TLS stack, and keep egress policy outside the agent's control.
Review the lifecycle, not only creation
For each secret type, write down:
create -> store -> delegate -> use -> observe -> rotate -> revoke -> delete
Then demand evidence for each arrow. A schema field proves persistence, not encryption. A generated token proves delegation, not expiry. A proxy proves mediation, not least privilege.
The runtime-token reuse behavior is also a reason to define model-switch semantics explicitly. If rebinding is intentional, ask what happens to an in-flight request using the prior model, how caches are keyed, and which audit event links old and new authority.
My acceptance gate would be: no provider key enters the task VM; the outbound host is approved after DNS and redirect handling; the runtime token is audience-, user-, model-, and VM-bound; expiry and revocation are tested; and logs prove the decision without exposing content.
Disclosure: I contribute to the MonkeyCode project. The observations and limitations above are based on the linked repository at the pinned commit and the local policy tests described here.
Top comments (0)