conductor-oss/conductor · error · RuntimeException
Refusing to forward credentials across an MCP redirect
Error message
Refusing to forward credentials across an MCP redirect
What it means
Security guard thrown by execute() when the request carries sensitive headers (Authorization, Cookie, or Proxy-Authorization) AND the redirect target is a different origin (scheme/host/port). The client deliberately withholds credentials across origins to prevent credential leakage to an attacker-controlled or unrelated host via a redirect. This is an intentional, non-bypassable protection.
Source
Thrown at ai/src/main/java/org/conductoross/conductor/ai/mcp/MCPService.java:394
private ResponsePayload execute(Request initialRequest) throws Exception {
Request request = initialRequest;
for (int redirects = 0; redirects <= 5; redirects++) {
try (Response response = httpClient.newCall(request).execute()) {
if (!response.isRedirect()) {
return new ResponsePayload(
response.code(),
response.header("Content-Type", "application/json"),
readBoundedBody(response.body()));
}
String location = response.header("Location");
if (location == null || request.url().resolve(location) == null) {
throw new RuntimeException(
"MCP server returned a redirect without a valid Location");
}
String target = request.url().resolve(location).toString();
if (hasSensitiveHeaders(request)
&& !isSameOrigin(request.url().toString(), target)) {
throw new RuntimeException(
"Refusing to forward credentials across an MCP redirect");
}
request = request.newBuilder().url(target).build();
}
}
throw new RuntimeException("MCP server exceeded the redirect limit");
}
private void addHeaders(Request.Builder builder, Map<String, String> headers) {
if (headers == null || headers.isEmpty()) {
return;
}
headers.forEach(
(name, value) -> {
if (name == null
|| value == null
|| name.indexOf('\r') >= 0
|| name.indexOf('\n') >= 0View on GitHub (pinned to cf7c3e4a8a)
Solutions
- Update serverUrl to point directly at the final origin so no cross-origin redirect occurs.
- If the cross-origin redirect is trusted and intentional, re-issue the call to the target origin yourself with credentials scoped appropriately (do not weaken this guard).
- Investigate unexpected cross-origin redirects — they may indicate a misconfigured proxy or an attack.
- Confirm the MCP server is not behind a redirect chain that crosses trust boundaries.
Defensive patterns
Strategy: validation
Validate before calling
// Pre-resolve the final origin and call it directly, so no cross-origin redirect occurs. // Do NOT attempt to weaken or bypass this guard for untrusted servers. java.net.URI target = java.net.URI.create(serverUrl); // ensure serverUrl is already the terminal origin the credentials are intended for
Try / catch
try {
mcpService.callTool(serverUrl, toolName, arguments, headers);
} catch (RuntimeException e) {
if (e.getMessage().contains("Refusing to forward credentials")) {
// SECURITY: do not bypass. Reconfigure serverUrl to the trusted final origin.
log.warn("Cross-origin credential redirect blocked for {}", serverUrl);
}
throw e;
} Prevention
- Never weaken or catch-and-continue this guard — it prevents credential leakage.
- Configure serverUrl to the canonical final origin so redirects don't cross origins.
- Treat unexpected cross-origin redirects as a possible attack/misconfiguration and investigate.
When it happens
Trigger: An authenticated request to origin A receives a 3xx redirect to origin B (different host/port/scheme); the client refuses to forward Authorization/Cookie/Proxy-Authorization to B. Common with SSO gateways that redirect to a different auth host, or with misconfigured/compromised servers attempting credential exfiltration via redirect.
Common situations: Server moved across hosts and the configured URL still hits the old host that redirects to the new one with a different origin; an open-redirect or SSRF-style setup where a redirect points elsewhere; legitimate cross-origin redirect flows that were not designed for.
Related errors
- agentUrl must use http or https, got: {scheme}
- agentUrl resolves to a cloud metadata address — SSRF blocked
- agentUrl resolves to a private/reserved address — SSRF block
- Access denied: path matches blocked prefix '{prefix}'
- Access denied: host '{host}' is blocked
AI-assisted analysis of conductor-oss/conductor@cf7c3e4a8a (2026-08-14).
Data as JSON: /api/errors/a56139997a5ebfca.
Report an issue: GitHub.