Skip to content

fix(mcp): enforce MCP feature flag on all token auth paths - #42186

Open
hacktron-app[bot] wants to merge 2 commits into
releasefrom
hacktron/fix-1870355c
Open

fix(mcp): enforce MCP feature flag on all token auth paths#42186
hacktron-app[bot] wants to merge 2 commits into
releasefrom
hacktron/fix-1870355c

Conversation

@hacktron-app

@hacktron-app hacktron-app Bot commented Sep 2, 2026

Copy link
Copy Markdown

Vulnerability (root cause)

McpTokenServiceCEImpl.authenticate(...) is the sink used by the MCP token authentication manager. It should reject authentication when the organization has the MCP feature disabled, but the enablement check (validateMCPEnabled()) was applied incorrectly, allowing a bypass (A07:2025):

  • Cache path (authenticateFromCache) — context loss / fail-open. The check was written as:
    Mono.just(user)
        .contextWrite(ReactiveSecurityContextHolder.withAuthentication(...))
        .contextWrite(ctx -> ctx.put(ORGANIZATION_ID, user.getOrganizationId()))
        .then(validateMCPEnabled())
        .thenReturn(user);
    Reactor context propagates upstream from the subscriber; the contextWrite operators only decorate the inner Mono.just(user) and never reach validateMCPEnabled(), which runs downstream of .then(). In EE, getCurrentUserOrganizationId() reads the request context, so it resolved empty, validateMCPEnabled() emitted nothing, and the check failed open — authentication succeeded even with MCP disabled.
  • Store path (authenticateFromStore) — the DB-backed fallback never called validateMCPEnabled() at all, bypassing the flag entirely.

Fix

Enforce the flag once, at the top of the public authenticate(...) method, on the caller's real reactive context, before either path runs:

return validateMCPEnabled()
        .then(authenticateFromCache(userKey, mcpKeyId)
                .switchIfEmpty(Mono.defer(() -> authenticateFromStore(userKey, mcpKeyId))));

validateMCPEnabled() errors with AppsmithException when MCP is disabled, which now propagates to the caller for both cache and store paths. The ineffective contextWrite(...)/.then(validateMCPEnabled()) block is removed from authenticateFromCache, along with the imports that became unused (ReactiveSecurityContextHolder, Authentication, UsernamePasswordAuthenticationToken, ORGANIZATION_ID).

This matches how create(...) already gates on validateMCPEnabled() and centralizes the check at the single shared entry point.

Verification

  • Traced the reactive flow: with MCP enabled, getCurrentUserOrganization() emits the org, validateMCPEnabled() completes, and the cache/store flow proceeds unchanged (legitimate tokens still authenticate). With MCP disabled, validateMCPEnabled() errors before any token lookup, so both paths are blocked.
  • Reviewed callers: authenticate has no EE override; authenticateFromCache/authenticateFromStore are private with no overrides, so the centralized gate covers CE and EE (McpTokenServiceImpl extends the CE impl).
  • Tests: fixed the existing should_throwError_whenMCPDisabledCacheHashMatchesAndUserIsEnabled test, which asserted via expectErrorSatisfies(...) but was missing the terminal .verify() (so it never subscribed and passed vacuously — the reason the bug went unnoticed). Added should_throwError_whenMCPDisabledAndStoreHashMatchesAndUserIsEnabled covering the store path. Could not execute the suite: the sandbox has no JDK/Maven available.

Automated fix by Hacktron for finding: https://app.hacktron.ai/appsmith-inc/findings/1870355c-c981-48ad-b8b0-c124d304abf0

sondermanish and others added 2 commits September 2, 2026 17:33
authenticate() gated the organization MCP feature flag only in the
cache path, and did so via contextWrite/.then(validateMCPEnabled())
whose context never propagated to the check, causing it to fail open;
the store path skipped the check entirely. Move validateMCPEnabled()
to the top of authenticate() so both cache and store paths enforce it
on the request's real reactive context, and drop the now-dead
contextWrite block and unused imports.
@hacktron-app
hacktron-app Bot requested a review from a team as a code owner September 2, 2026 12:18
@hacktron-app
hacktron-app Bot requested a review from sondermanish September 2, 2026 12:18
Base automatically changed from feat/mcp-base-server to release September 2, 2026 17:15
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