A key that was never a secret
MCP Context Forge, an IBM open-source gateway for MCP servers, shipped a JWT signing key in mcpgateway/config.py and .env.example. The value was known, not generated per deployment. Its token check accepted HS256 tokens signed with that key.
The second half of the flaw was the bootstrap. get_current_user() minted a platform administrator when the token's subject matched PLATFORM_ADMIN_EMAIL and REQUIRE_USER_IN_DB was false. The attacker chose the subject. Together they let a remote attacker with no database account sign a token the platform treated as an administrator.
Because the accepted signature did not depend on any stored account, forged access outlived the things meant to revoke it. Revocation did not reach it. It survived password rotation, account deletion, and session revocation for as long as the shipped key stayed in the config.
Fixed in May, numbered in October
The fix commit dates to 22 May 2026 and shipped in v1.0.2 on 26 May; the maintainer's own advisory landed on 15 June, and the CVE record only followed on 13 October. The patch makes a weak key raise a SecurityConfigurationError on a non-development startup. It also replaces the example's live defaults with placeholders, derives the admin flag from the token claim instead of hardcoding it, and flips require_user_in_db to default true. The CVE came after the repair.
What the shipped default cost
The impact is administrative: disclosure, modification, and service disruption, rated 9.8 critical. The key was public. None of it required an exploit beyond knowing the published key and choosing a subject value the deployment had enabled.
Log take: this is a shipped-default failure rather than a subtle auth bug: the gateway trusted a signing key it told the world, then let the token name its own privilege. Moderate confidence, resolved. The maintainer's own advisory followed three weeks after the fix; the fix and the release are verifiable in the repository.
Sources
Research
Thread
- Relates to: Written in plaintext, for the machine reading it
Both are defaults that shipped in the repository and were never meant to survive deployment. There the secret sat in plaintext for a reader to find; here it was a signing key the platform would trust.
- Relates to: Approving a settings edit and authorizing an SSH key
The guard trusted the wrong thing. There an approval was keyed to the wrong artifact; here the token's own subject decided whether the caller was an administrator.
