Restrict hosted MCP credentials to local environments (#36306)

## Why

Executor-owned MCP servers must not receive hosted ChatGPT actor credentials or credentials from the host's OAuth store.

## What changed

- Provide the ChatGPT auth provider and consult stored OAuth credentials only for MCP servers in the local environment.
- Require non-local servers configured with `auth = "chatgpt"` to supply a non-empty, valid static `Authorization` header. Reject environment-backed authorization so host secrets are not resolved for an executor-owned server.
- Report unsupported authentication and fail startup before connecting when an executor-owned server has no acceptable explicit authorization.

## Testing

Add coverage for local credential forwarding, non-local credential isolation, static header validation, auth status, OAuth lookup avoidance, and startup rejection.

GitOrigin-RevId: e18f1878f260c93d9babd390a5a7eac86172299b
This commit is contained in:
jif authored and copyberry committed 2026-07-31 10:42:02 +00:00
1 parent f0c30e528a
commit bf4d3f51ea
5 files changed
+310 -2

No files matched your search

+10
View File
@@ -30,6 +30,7 @@ use crate::pagination::collect_paginated;
use crate::runtime::McpRuntimeContext;
use crate::runtime::emit_duration;
use crate::server::EffectiveMcpServer;
use crate::server::has_explicit_http_authorization;
use crate::tool_catalog_cache::McpToolCatalogCacheContext;
use crate::tool_catalog_cache::McpToolCatalogFetchTicket;
use crate::tools::ToolInfo;
@@ -39,6 +40,7 @@ use async_channel::Sender;
use codex_api::SharedAuthProvider;
use codex_async_utils::CancelErr;
use codex_async_utils::OrCancelExt;
use codex_config::McpServerAuth;
use codex_config::McpServerConfig;
use codex_config::McpServerTransportConfig;
use codex_config::types::AuthKeyringBackendKind;
@@ -995,6 +997,14 @@ async fn make_rmcp_client(
protocol_mode: McpProtocolMode,
) -> Result<RmcpClient, StartupOutcomeError> {
let config = server.config().clone();
if matches!(config.auth, McpServerAuth::ChatGpt)
&& !config.is_local_environment()
&& !has_explicit_http_authorization(&config)
{
return Err(StartupOutcomeError::from(anyhow!(
"executor-owned MCP server `{server_name}` cannot use hosted ChatGPT authentication; configure executor-owned credentials instead"
)));
}
let resolved_environment =
resolved_environment.map_err(|err| StartupOutcomeError::from(anyhow!(err)))?;
let is_local_environment = config.is_local_environment();