Severity: CRITICAL
Filing as a Design Issue per the repo's prefer-issue-over-PR norm so you can red/green the approach before I PR.
What
agent-brain-server's FastAPI app has zero authentication on any endpoint:
POST /index, POST /index/add, DELETE /index, GET /query, POST /query, GET /query/count, GET /index/folders, GET /index/jobs, GET /index/cache are all open.
agent-brain-server/agent_brain_server/api/main.py instantiates FastAPI() with no auth dependency. Grep for HTTPBearer, APIKeyHeader, Depends(verify_*) returns zero hits in the API surface.
- The
127.0.0.1 default bind is NOT an authorization control. Any local process on the same machine (any browser tab with the right Origin, any rogue subprocess, any other agent) can read the entire index or wipe it.
Threat model
Single dev box, multiple projects, multiple LLM agents running concurrently (which is the actual agent-brain deployment pattern based on your multi-instance architecture):
- Agent in project A queries
/query and reads embedded chunks of project B's source.
- Any local script can
curl -X DELETE http://127.0.0.1:8000/index and nuke the index.
- Combined with the CORS wildcard (separate issue), a malicious web page can do all of the above from the browser via DNS rebinding.
OWASP API1:2023 (BOLA) + API2:2023 (Broken Auth).
Proposed fix
Two-layer, opt-out friendly for local-only dev:
- Add
API_KEY: SecretStr | None = None to config/settings.py.
- Add
app/security.py with a verify_api_key FastAPI dependency reading X-API-Key header. If settings.API_KEY is None, the dependency is a no-op (preserves the current local-dev experience for solo users); if set, it 401s on missing/wrong.
- Apply the dependency to every router except
/health, /health/status, /docs, /redoc, /openapi.json via APIRouter(dependencies=[Depends(verify_api_key)]) per file.
- CLI generates a key on
agent-brain init (32 bytes urlsafe), writes to .agent-brain/runtime.json mode 600 (see also #state-dir-perms issue), and reads it for all CLI calls via X-API-Key.
.env.example documents API_KEY= and the README gets a one-liner: "for shared hosts, set API_KEY to require auth on the server."
- Optional hardening: refuse to start if
API_HOST is anything other than 127.0.0.1 and API_KEY is unset. Loud warn-and-continue if both 127.0.0.1 and no key (default dev case).
Test strategy
- New fixture in
tests/conftest.py: app_with_api_key that sets API_KEY and returns a test client with the right header
- Per-router: 401 on missing header, 401 on wrong key, 200 on correct key
- Existing tests stay green via the no-API_KEY default path
- Contract tests for both modes against Chroma and Postgres backends
Files touched (estimate)
agent_brain_server/config/settings.py (+1 field)
agent_brain_server/api/security.py (new, ~40 LOC)
agent_brain_server/api/routers/{health,query,index,jobs,folders,cache}.py (router-level dependency)
agent_brain_cli/agent_brain_cli/client/*.py (send X-API-Key)
agent_brain_cli/agent_brain_cli/commands/init.py (generate + store key)
.env.example, README.md (docs)
- Tests as above
Open questions for you
- OK with the "no key = no auth" default? Preserves your single-user dev experience. Alternative: refuse to start without a key (breaking change, but stronger default).
- OK with
X-API-Key header vs Authorization: Bearer? Header is simpler; Bearer is more conventional.
- Should
/docs be gated too in non-DEBUG mode, or left open? (Filed as a separate issue.)
Happy to do the PR end-to-end once you green-light the approach. Will run task before-push + task pr-qa-gate before pushing. Plan to branch security/issue-NNN-api-key-auth to match your <type>/issue-<N>-<slug> convention.
- Jeremy Longshore
intentsolutions.io
Severity: CRITICAL
Filing as a Design Issue per the repo's prefer-issue-over-PR norm so you can red/green the approach before I PR.
What
agent-brain-server's FastAPI app has zero authentication on any endpoint:POST /index,POST /index/add,DELETE /index,GET /query,POST /query,GET /query/count,GET /index/folders,GET /index/jobs,GET /index/cacheare all open.agent-brain-server/agent_brain_server/api/main.pyinstantiatesFastAPI()with no auth dependency. Grep forHTTPBearer,APIKeyHeader,Depends(verify_*)returns zero hits in the API surface.127.0.0.1default bind is NOT an authorization control. Any local process on the same machine (any browser tab with the right Origin, any rogue subprocess, any other agent) can read the entire index or wipe it.Threat model
Single dev box, multiple projects, multiple LLM agents running concurrently (which is the actual
agent-braindeployment pattern based on your multi-instance architecture):/queryand reads embedded chunks of project B's source.curl -X DELETE http://127.0.0.1:8000/indexand nuke the index.OWASP API1:2023 (BOLA) + API2:2023 (Broken Auth).
Proposed fix
Two-layer, opt-out friendly for local-only dev:
API_KEY: SecretStr | None = Nonetoconfig/settings.py.app/security.pywith averify_api_keyFastAPI dependency readingX-API-Keyheader. Ifsettings.API_KEYis None, the dependency is a no-op (preserves the current local-dev experience for solo users); if set, it 401s on missing/wrong./health,/health/status,/docs,/redoc,/openapi.jsonviaAPIRouter(dependencies=[Depends(verify_api_key)])per file.agent-brain init(32 bytes urlsafe), writes to.agent-brain/runtime.jsonmode 600 (see also #state-dir-perms issue), and reads it for all CLI calls viaX-API-Key..env.exampledocumentsAPI_KEY=and the README gets a one-liner: "for shared hosts, setAPI_KEYto require auth on the server."API_HOSTis anything other than127.0.0.1andAPI_KEYis unset. Loud warn-and-continue if both127.0.0.1and no key (default dev case).Test strategy
tests/conftest.py:app_with_api_keythat setsAPI_KEYand returns a test client with the right headerFiles touched (estimate)
agent_brain_server/config/settings.py(+1 field)agent_brain_server/api/security.py(new, ~40 LOC)agent_brain_server/api/routers/{health,query,index,jobs,folders,cache}.py(router-level dependency)agent_brain_cli/agent_brain_cli/client/*.py(sendX-API-Key)agent_brain_cli/agent_brain_cli/commands/init.py(generate + store key).env.example,README.md(docs)Open questions for you
X-API-Keyheader vsAuthorization: Bearer? Header is simpler; Bearer is more conventional./docsbe gated too in non-DEBUG mode, or left open? (Filed as a separate issue.)Happy to do the PR end-to-end once you green-light the approach. Will run
task before-push+task pr-qa-gatebefore pushing. Plan to branchsecurity/issue-NNN-api-key-authto match your<type>/issue-<N>-<slug>convention.intentsolutions.io