Xerj Console API: a bearer token could mint successor API tokens past the passkey gate (CVE-2026-97406, 9.1); fixed v1.0.0-rc.98
TL;DR
Xerj, a Rust search engine and MCP server for agents (17.7k stars), accepted an API bearer token on the Console API route that mints new API tokens, a route meant to require a passkey-authenticated browser session, so anyone holding one leaked token could mint persistent successor tokens that revoking the original would not touch (CVE-2026-97406, CERT/CC VU#645818, 2026-10-20; GitHub Advisory Database 9.1 Critical, unreviewed). The vendor did not answer CERT/CC's 2026-08-13 notice and the note still says no patch, but PR #2003 (merged 2026-10-21) gates the minting, revocation, invitation, passkey-deletion and logout routes behind a passkey session by default, and the maintainer states that v1.0.0-rc.98 (2026-10-22) carries it. Upgrade to rc.98 or later and rotate every API token issued before the upgrade, because the fix does not revoke tokens minted through the gap.
What happened
- 2026-08-13. CERT/CC notifies the vendor (the note's "vendor notified" date). No reply.
- 2026-10-20. CERT/CC publishes VU#645818 and the CNA record CVE-2026-97406: "XERJ Console API bearer tokens can bypass the passkey-only authentication requirement and directly invoke the API-token creation endpoint, allowing unauthorized minting of persistent successor credentials." Credit: Shiran Guez. The note says the platform "lacks hierarchical revocation", so revoking a parent token does not invalidate its descendants, that a stolen owner token keeps full administrative authority, and that an attacker could issue an invitation, redeem it, and enrol their own passkey. The record's
affectedlists one version,v1.0.0-rc.11, with no range and no fix. The GitHub Advisory Database entry GHSA-vjpr-qxjc-7crv (published 2026-10-20, updated 10-29) prints CVSS 3.1 9.1AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N, CWE-306, and "Unknown" for package and versions. - 2026-10-21. PR #2003, "fix(console-api): require a passkey session to mint API tokens (CVE-2026-97406)", merges as commit 050a12e. Per the PR and the repository's
docs/SECURITY_MODEL.md, a bearer token now gets 403 before the handler runs onPOST /auth/api-tokens,DELETE /auth/api-tokens/:id,POST /auth/magic/issue,DELETE /auth/passkeys/:idandPOST /auth/logout; ordinary reads and writes keep working on a bearer token. The check sits in the session extractor with no flag, so it is on by default. The same day, issue #2020 asks the maintainer for a vendor statement to CERT/CC, a release carrying the commit, and a GHSA, and notes that "the fix does not revoke tokens or passkeys minted before the upgrade." - 2026-10-22. v1.0.0-rc.98 is released; the maintainer's 2026-10-23 comment on #2020 says it contains the fix commit.
- 2026-10-23. The maintainer posts a statement on the issue, not to CERT/CC: "this is a low-risk issue. It did not downgrade security, and exploiting it required an already-leaked token", and closes the issue as resolved.
- 2026-10-27. CERT/CC revises the note (revision 2); it still reads "no patch, vendor unreachable". v1.0.0-rc.100 is released the same day; its notes do not mention the fix. The vendor tab on the repository has no advisory; the GHSA id is the database's own.
Severity. Two readings disagree. The database prints 9.1 Critical (unauthenticated in the vector); the maintainer calls it low-risk because the path starts from a token the attacker already holds. This file says high: the precondition is real, but a Xerj token is exactly what an agent or MCP client stores in its config, and the bug turned a revocable leak into persistent access. status: patched rests on a default-on gate in a merged commit and the maintainer's statement that rc.98 carries it; the release notes of rc.98 and rc.100 do not name it, and this file did not diff the tag.
Why it matters. Xerj is built to sit behind agents ("Works with Claude Code, Cursor and any MCP client"), which means its tokens live in ~/.claude.json, .cursor/mcp.json and CI environments, the places every credential-stealing package this corpus tracks reads first. A stolen token that can mint its own successors survives the rotation the owner thinks they did.
Am I affected?
xerj --version 2>/dev/null # anything before v1.0.0-rc.98
grep -rn 'xerj' ~/.claude.json .cursor/mcp.json .mcp.json 2>/dev/null # where a token would sit
- Any Xerj instance whose console was reachable on a release before rc.98, and any API token issued before the upgrade, is in scope. The Console API's token list (
GET /auth/api-tokens, metadata only) shows tokens you did not mint.
If you are affected
- Upgrade to v1.0.0-rc.98 or later (rc.100 is newest as of 2026-10-30).
- From a passkey session, list and revoke every API token, then issue new ones; the fix does not revoke tokens minted before it. Remove passkeys you did not enrol.
- Treat anything the instance indexed as read by whoever held the token: if an MCP server was malicious covers the config-file and token rotation steps for the clients.
Prevention
- Bind the console to loopback or an authenticated proxy; the README's default is loopback: MCP hygiene.
- Scope and rotate the tokens agents hold: credential hygiene.
Sources
- CERT/CC — VU#645818: Xerj Console API authentication bypass leads to unauthorized credential minting — fetched 2026-10-30: published 2026-10-20, revised 2026-10-27, vendor notified 2026-08-13, the mechanism, the invitation and passkey-enrolment consequence, "no patch", "vendor could not be reached", credit Shiran Guez.
- CVE Services — CVE-2026-97406 — fetched 2026-10-30: CNA certcc, published 2026-10-20, updated 10-29, affected
v1.0.0-rc.11, the note as the only reference, no metrics. - GitHub Advisory Database — GHSA-vjpr-qxjc-7crv — fetched 2026-10-30: unreviewed, 9.1 and vector, CWE-306, package and versions unknown, EPSS 0.223%.
- xerj-org/xerj — PR #2003 — fetched 2026-10-30: merged 2026-10-21 as 050a12e, the five gated routes, no flag, the CVE and VU references.
- xerj-org/xerj — issue #2020 — fetched 2026-10-30: opened 2026-10-21, the four asks, the maintainer's 2026-10-23 comments (rc.98 carries the fix; "low-risk"), closed 2026-10-23.
- xerj-org/xerj — docs/SECURITY_MODEL.md — fetched 2026-10-30: the "Console credentials: a passkey session is not an API token" section citing the CVE and VU, the route table, "A bearer token cannot mint a descendant".
- xerj-org/xerj — releases — fetched 2026-10-30: v1.0.0-rc.100 dated 27 Oct marked Latest, notes without the fix; the tab otherwise lists corpus packs. Security advisories tab: none published.
- xerj-org/xerj — repository — fetched 2026-10-30: "AI search engine and MCP server for bots and agents", 17.7k stars, "Works with Claude Code, Cursor and any MCP client", loopback default, Apache-2.0.