Skip to content

Gate agent-write endpoints on user state for non-agent roles (benchmarks._require_agent_bearer) #190

Description

@jgruberf5

Gap (mwiget, non-blocking note on #186)

backend/routes/benchmarks.py::_require_agent_bearer authorizes the agent-facing mutating endpoints (register / ingest) on the role claim alone, without loading a User — the same fail-open shape #186 fixed for the WebSocket validators. A deactivated or must-change-password operator/admin whose JWT is still valid can keep writing to these endpoints until the token expires.

Why it is not a drop-in "same fix"

Validated the code before acting: _AGENT_WRITE_ROLES = {agent, operator, admin}, and agent tokens intentionally have no User row — their sub is an agent name or a service identity, not a username:

  • startup_steps.py: {"sub": "forge-builtin-agent", "role": "agent"}
  • benchmark_agent_provision_service.py: {"sub": agent.name, "role": "agent", "agent_id": ...}
  • tests also cover {"sub": "forge-agent-service", "role": "admin"} and role=admin+agent_id service tokens.

So naively calling token_user_state(token) here (as the WS gate does) would reject every legitimate agent/service token and break benchmark ingestion. This is why it was left out of #186 rather than rushed into an approved PR.

Proposed fix (own PR, with tests)

Carve out by role:

  • role == "agent" (and service tokens without a username sub): keep the claim-only check — there is no User to load.
  • role in {"operator", "admin"} with a username sub: resolve via token_user_state and refuse on None / is_active == False / must_change_password, matching get_current_user.

Extend backend/tests/unit/test_benchmark_agent_auth.py accordingly (deactivated operator refused; agent/service tokens still accepted). Reference: token_user_state in services/auth_service.py.

https://claude.ai/code/session_01UpRYiFserdBE5ESHn759N4

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething is broken or behaves incorrectlysecuritySecurity hardening, CVE tracking, or an authz/authn gap

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions