Skip to content

fix: add optional API key authentication to all mutating HTTP endpoints#91

Closed
Joshua-Medvinsky wants to merge 1 commit into
themanojdesai:mainfrom
Joshua-Medvinsky:fix/unauthenticated-routes
Closed

fix: add optional API key authentication to all mutating HTTP endpoints#91
Joshua-Medvinsky wants to merge 1 commit into
themanojdesai:mainfrom
Joshua-Medvinsky:fix/unauthenticated-routes

Conversation

@Joshua-Medvinsky

Copy link
Copy Markdown

Summary

  • Adds an optional api_key parameter to create_flask_app()
  • When set, all mutating POST routes (/a2a, /stream, /a2a/tasks/send, /a2a/tasks/cancel, /) enforce Authorization: Bearer <token> authentication
  • Returns HTTP 401 with a JSON error body for unauthorised requests
  • Read-only GET routes (agent card, health, metadata) remain open for service-discovery compatibility with the A2A spec
  • Fully backward-compatible: callers that omit api_key see no behaviour change

Vulnerability

All POST endpoints in the A2A server were completely unauthenticated. Any client on the network could:

  • Send arbitrary agent messages (/a2a POST)
  • Create or cancel tasks without restriction (/a2a/tasks/send, /a2a/tasks/cancel)
  • Trigger streaming sessions (/stream)

The server also binds to 0.0.0.0:5000 by default, making every interface reachable.

Severity: High
CWE: CWE-306 (Missing Authentication for Critical Function)

Usage

from python_a2a.server.http import create_flask_app

app = create_flask_app(my_agent, api_key="s3cr3t-token")
app.run(host="0.0.0.0", port=5000)

Clients must then include:

Authorization: Bearer s3cr3t-token

Test plan

  • POST /a2a without header → 401
  • POST /a2a with correct bearer → 200
  • POST /a2a/tasks/send without header → 401
  • POST /a2a/tasks/cancel without header → 401
  • GET /agent.json (no token) → 200 (read-only routes unaffected)
  • api_key=None (default) → all routes behave as before

Introduces an api_key parameter to create_flask_app(). When set, every
POST route (/a2a, /stream, /tasks/send, /tasks/cancel, /) requires an
Authorization: Bearer <token> header and returns 401 otherwise.

Read-only GET routes (agent card, health, metadata) are intentionally
left unauthenticated so service-discovery clients can operate without
credentials, consistent with the A2A spec.
@Joshua-Medvinsky

Copy link
Copy Markdown
Author

Closing — this exceeded our 2-PR-per-run cap. The authentication concern is valid but better raised as a separate issue by the maintainers once the critical RCE fixes (#89, #90) are reviewed.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant