Repository navigation
security(a2a-server): HTTP API never enforces authentication, and the only auth check compares against hardcoded public credentials ('valid-token', 'admin:password') #29001
Description
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:
- Authentication is never enforced. The
userBuilderresult is only attached to the A2A call context by@a2a-js/sdk(jsonRpcHandlerbuildscontext = ctxBuilder({ ..., user })); nothing inpackages/a2a-serverever rejects a request whenisAuthenticated === false. Verified by:app.test.ts/endpoints.test.tssuccessfully exercise/executeCommand,/tasks,/tasks/metadataetc. with no Authorization header at all; there is not a single 401 assertion in the package.grep isAuthenticated packages/a2a-server/srconly shows where it is set to true, never checked.
- 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
securitySchemesfromcoderAgentCardand 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—customUserBuilderwith 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 advertisesbearerAuth/basicAuthsecuritySchemes+securityrequirementnode_modules/@a2a-js/sdk/dist/server/express/index.js(jsonRpcHandler) — user attached to call context without rejectionpackages/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.
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsClosed
Activity
gemini-cli commentedon Sep 8, 2026
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.
gemini-cli commentedon Sep 9, 2026
Effort Analysis:
The
@google/gemini-cli-a2a-serverpackage's authentication logic inpackages/a2a-server/src/http/app.ts(lines 94-123) currently lacks any enforcement mechanism, as theisAuthenticatedproperty returned by thecustomUserBuilderis 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 whenisAuthenticatedis false. Furthermore, the hardcoded credentials'valid-token'and'admin:password'inapp.tsmust be removed and replaced with a secure configuration mechanism, requiring modifications to the configuration loading logic inpackages/a2a-server/src/config/config.ts. The existing test suite inpackages/a2a-server/src/http/app.test.tsindiscriminately usesexpect(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 theeffort/mediumguidelines for integration and cross-component refactors.gemini-cli commentedon Sep 25, 2026
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!