Skip to content

security(a2a-server): HTTP API never enforces authentication, and the only auth check compares against hardcoded public credentials ('valid-token', 'admin:password') #29001

Closed as not planned

Description

@aniruddhaadak80

What happened?

The @google/gemini-cli-a2a-server HTTP server (published to npm with the gemini-cli-a2a-server bin) does not actually enforce authentication on any endpoint, even though its Agent Card advertises bearer/basic security schemes. Additionally, the only authentication logic that exists uses hardcoded public demo credentials checked against values committed to this public repository.

packages/a2a-server/src/http/app.ts (main):

const customUserBuilder: UserBuilder = async (req: Request) => {
  const auth = req.headers['authorization'];
  ...
  // 1. Bearer Auth
  if (auth.startsWith('Bearer ')) {
    const token = auth.substring(7);
    if (token === 'valid-token') {            // <- hardcoded public token
      return { userName: 'bearer-user', isAuthenticated: true };
    }
  }

  // 2. Basic Auth
  if (auth.startsWith('Basic ')) {
    const credentials = Buffer.from(auth.substring(6), 'base64').toString();
    if (credentials === 'admin:password') {   // <- hardcoded public creds
      return { userName: 'basic-user', isAuthenticated: true };
    }
  }
  return new UnauthenticatedUser();
};

Two problems:

  1. Authentication is never enforced. The userBuilder result is only attached to the A2A call context by @a2a-js/sdk (jsonRpcHandler builds context = ctxBuilder({ ..., user })); nothing in packages/a2a-server ever rejects a request when isAuthenticated === false. Verified by:
    • app.test.ts / endpoints.test.ts successfully exercise /executeCommand, /tasks, /tasks/metadata etc. with no Authorization header at all; there is not a single 401 assertion in the package.
    • grep isAuthenticated packages/a2a-server/src only shows where it is set to true, never checked.
  2. Even if enforcement were added, the credentials are public constants ('valid-token', 'admin:password') known to anyone who can read this repo, so they provide zero security value as implemented.

Impact: any local process that can reach http://localhost:<port>/ can invoke the full agent surface unauthenticated — POST /executeCommand (executes registered commands, including streaming command execution), task creation via JSON-RPC (/tasks), etc., driving an agent with workspace access. The localhost-only bind (expressApp.listen(port, 'localhost', ...) at app.ts:411) limits exposure to local processes and container/host-boundary confusion scenarios (e.g., host.docker.internal mapping in getIdeServerHost()-style setups), but "any code on the machine can drive the agent" still violates the trust boundary the advertised securitySchemes imply.

What did you expect to happen?

Either:

  • Enforce authentication in middleware before all routes (reject 401 when !user.isAuthenticated), and source credentials from configuration/environment with no defaults; or
  • If the server is intended to be unauthenticated-by-design for local dev, remove the misleading securitySchemes from coderAgentCard and delete the hardcoded credential check so downstream users don't assume protection that doesn't exist.

Client information

Source-level finding verified against upstream main at commit 5411f113c; cross-checked the @a2a-js/sdk@1.0.1 express handler behavior (user is attached to context, never rejected).

Platform: applies to all platforms; affects the published @google/gemini-cli-a2a-server package.

Login information

Not applicable.

Anything else we need to know?

Sources:

  • packages/a2a-server/src/http/app.ts:96-122 — customUserBuilder with hardcoded 'valid-token' / 'admin:password'
  • packages/a2a-server/src/http/app.ts:411 — localhost-only listener (exposure bound)
  • packages/a2a-server/src/http/app.ts:52-56 — Agent Card advertises bearerAuth/basicAuth securitySchemes + security requirement
  • node_modules/@a2a-js/sdk/dist/server/express/index.js (jsonRpcHandler) — user attached to call context without rejection
  • packages/a2a-server/src/http/app.test.ts / endpoints.test.ts — endpoints exercised without auth headers; no 401 tests
  • Duplicate check: searched issues/PRs for "a2a authentication", "valid-token", "a2a auth", "hardcoded" — no existing report or fix found.

Activity

  1. added
    priority/p1Important and should be addressed in the near term.
    and removed
    status/need-triageIssues that need to be triaged by the triage automation.
    on Aug 31, 2026
  2. added theissue type on Aug 31, 2026
  3. added
    area/coreIssues related to User Interface, OS Support, Core Functionality
    priority/p2Important but can be addressed in a future release.
    and removed
    area/securityIssues related to security
    priority/p1Important and should be addressed in the near term.
    on Sep 8, 2026
  4. gemini-cli commented on Sep 8, 2026

    @gemini-cli
    Contributor

    This is a bug related to Windows path handling in core tools. The provided CLI version (0.1.7) is significantly outdated compared to the current version (0.61.0). Please verify if this issue persists in the latest version of Gemini CLI.

  5. gemini-cli commented on Sep 9, 2026

    @gemini-cli
    Contributor

    Effort Analysis:
    The @google/gemini-cli-a2a-server package's authentication logic in packages/a2a-server/src/http/app.ts (lines 94-123) currently lacks any enforcement mechanism, as the isAuthenticated property returned by the customUserBuilder is never checked before processing requests in routes such as /tasks, /executeCommand, and /listCommands. The implementation requires adding a new Express middleware to intercept these routes and return a 401 Unauthorized status when isAuthenticated is false. Furthermore, the hardcoded credentials 'valid-token' and 'admin:password' in app.ts must be removed and replaced with a secure configuration mechanism, requiring modifications to the configuration loading logic in packages/a2a-server/src/config/config.ts. The existing test suite in packages/a2a-server/src/http/app.test.ts indiscriminately uses expect(200) without providing authentication headers, so the fix also necessitates a comprehensive update of the tests to include valid auth headers and verify rejection of unauthorized requests. This cross-component work spanning routing, configuration, and testing, combined with the security-critical nature of the fix, aligns with the effort/medium guidelines for integration and cross-component refactors.

  6. added
    effort/medium2-3 days: UI state, async flow, cross-component refactors
    area/extensionsIssues related to Gemini CLI extensions capability
    and removed
    area/coreIssues related to User Interface, OS Support, Core Functionality
    on Sep 9, 2026
  7. gemini-cli commented on Sep 25, 2026

    @gemini-cli
    Contributor

    This item was marked as needing more information and has not received a response in 14 days. Closing it for now. If you still face this problem, feel free to reopen with more details. Thank you!

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

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions