Repository navigation
Conversation
ChatAgentOpenAPIServer kept every agent in one flat registry keyed by a client-chosen agent_id, and every agent-scoped handler only checked existence — never who was asking (issue camel-ai#4352, BOLA). Any client could enumerate the full agent inventory via list_agent_ids, read any agent's history (system prompts, tool results), reset its memory, or delete it; the defect persisted even behind an authentication layer because handlers never bound an agent to an identity. - add api_keys to ChatAgentOpenAPIServer: requests must present a configured key via 'Authorization: Bearer <key>' or 'X-API-Key' - agents are owned by the key that created them (only key hashes are stored); history/step/astep/reset/delete return 404 across owners without disclosing existence, and list_agent_ids is scoped to the caller's own agents - secure by default: with no api_keys configured the server mints one ephemeral key (exposed as .api_key); pass api_keys=[] explicitly for the legacy unauthenticated single-user mode - cross-owner /init conflicts return 409 instead of silently adopting the existing agent - update the existing tests to authenticated clients and add coverage: 401 paths, bearer/header auth, inventory scoping, cross-owner 404s, secret non-disclosure, 409 conflicts, ephemeral-key and open modes Fixes camel-ai#4352
Contributor
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Advanced Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
The CodeQL check run crashed at startup (failed in 5s) while the CodeQL Advanced workflow itself passed all Analyze jobs; this empty commit re-triggers the analysis so the check re-registers.
…SHA-256 CodeQL flags plain SHA-256 over API keys as weak sensitive-data hashing. Key the digest with a random per-instance pepper (HMAC-SHA256) instead: ids stay stable for the server's lifetime — all the ownership mapping needs — while the owners map resists offline recovery of the keys.
CodeQL's sensitive-data hashing rule also flags the HMAC variant, and the owners map gained little from hashing anyway: the configured keys already live in memory for authentication. Ownership now records the validated key itself, agent-scoped checks use constant-time hmac.compare_digest, and no hash of key material is computed anywhere.
This was referenced Sep 29, 2026
Subagent review findings on this branch: - non-ASCII X-API-Key/Authorization values raised TypeError inside hmac.compare_digest (str form is ASCII-only), turning a malformed request into a 500; keys are now compared as UTF-8 bytes so any wire value is a clean 401 - concurrent /init calls with the same agent_id raced between the existence check and the registry write (model construction takes long enough) and could double-register across owners; the check -> create -> register sequence is now serialized by a lock - the official example was broken by the auth change (bare TestClient got 401); both example sites now present server.api_key and document the api_keys option Also: 401 responses carry WWW-Authenticate: Bearer (RFC 6750), the open mode logs a warning at startup, list_agent_ids iterates a snapshot with constant-time owner comparison, delete uses pop with defaults, and new tests cover non-ASCII keys, authenticated-but- missing agents, open-mode shared identity, and the 401 header. Review findings credit: subagent adversarial review.
Follow-up to the delta review: the non-ASCII fix covered only _verify_api_key — the three ownership comparisons (get/conflict/list) still used str-form hmac.compare_digest, so a configured non-ASCII key authenticated fine and then every ownership path 500'd. All key equality now goes through a shared _keys_equal helper that compares UTF-8 bytes and treats unencodable values as unequal. Also fixes the two inline example functions (listing/delete and multi-agent turns) that still constructed a bare TestClient and got 401 after the auth change.
… unencodable key ids Modified-line coverage in agent_openapi_server.py reaches 100%: - tools lookup loop (registered hit + unknown-tool 400) - step/astep HTTPException re-raise guards (fake agent raising 409; sync step must not run for the async endpoint) - _keys_equal with lone-surrogate (unencodable) values returns False instead of raising
5 of 7 tasks
2 of 3 tasks
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Fixes #4352.
ChatAgentOpenAPIServerkept every agent in one flat registry keyed by a client-chosenagent_id, and every agent-scoped handler (/astep,/delete,/step,/reset,/history) only checked existence — never who was asking. Any client could enumerate the full agent inventory vialist_agent_ids, read any agent's history (system prompts, user messages, tool results), reset its memory, or delete it. As the report notes, the defect persists even behind an authentication layer because the handlers never bind an agent to an identity.Fix
api_keysconstructor argument. Requests must present a configured key viaAuthorization: Bearer <key>orX-API-Key: <key>; anything else gets401.history,step,astep,resetanddeletereturn404across owners — without disclosing that the agent exists — andlist_agent_idsreports only the caller's own agents.api_keysis omitted the server mints one ephemeral key, exposed as.api_keyfor operators to distribute. Passing a non-empty list enables multi-tenant ownership; passingapi_keys=[]explicitly restores the legacy unauthenticated mode (single-user, trusted-network deployments)./initwith an existing id now returns409instead of silently reporting "already exists" to a non-owner.Behavior change (intentional)
Clients that previously called the API without credentials now receive
401unless the operator passesapi_keys=[]. The auto-generated key keeps single-user deployments working with a one-line change on the client side.Real-service verification
The full attack chain from the report was replayed against a real
uvicornserver started from this branch (15/15 assertions passing): unauthenticated requests rejected; victim agent created with a secret system prompt; second client sees only its own inventory, gets404on history/reset/delete/astep of the victim, and the secret is never disclosed; the owner retains full access; deletion frees the id.Testing
X-API-Keyboth accepted, ephemeral-key mode, open mode, inventory scoping, cross-owner404s, secret non-disclosure,409conflict, delete/recreate cyclepytest test/services/test_agent_openapi_server.py: 13 passed locally (4model_backendtests need real provider credentials and fail identically onmasterin a credential-less environment)