CoplayDev/unity-mcp · error · Exception

{context}: refusing to send credentials to an unexpected hos

Error message

{context}: refusing to send credentials to an unexpected host in URL '{url}' (expected https://{allowedHost}).

What it means

Thrown by ProviderHttp.RequireHost, a credential-leak guard. Every auth-bearing request URL is routed through it so that a malicious or MITM'd provider response (e.g. a rogue response_url or download URL) cannot redirect the API key to an attacker-controlled host. It requires an absolute https URL whose host exactly equals allowedHost; anything else throws. The message is scrubbed of the key. This is a deliberate security fail-fast, not a bug.

Source

Thrown at MCPForUnity/Editor/Services/AssetGen/Providers/ProviderHttp.cs:26

    /// <summary>
    /// Shared HTTP-response helpers for provider adapters: read the response text (falling back to
    /// a UTF-8 decode of the raw body) and truncate long bodies for inclusion in error messages.
    /// </summary>
    internal static class ProviderHttp
    {
        /// <summary>
        /// Throw unless <paramref name="url"/> is an absolute https URL whose host is exactly
        /// <paramref name="allowedHost"/>. Adapters route every auth-bearing request URL through
        /// this so a malicious/MITM'd provider response (e.g. a rogue response_url) can't redirect
        /// the API key to an attacker host. The error is scrubbed of the key.
        /// </summary>
        public static void RequireHost(string url, string allowedHost, string apiKey, string context)
        {
            if (!Uri.TryCreate(url, UriKind.Absolute, out Uri u)
                || u.Scheme != Uri.UriSchemeHttps
                || !string.Equals(u.Host, allowedHost, StringComparison.OrdinalIgnoreCase))
            {
                throw new Exception(SecretRedactor.Scrub(
                    $"{context}: refusing to send credentials to an unexpected host in URL '{url}' (expected https://{allowedHost}).",
                    apiKey));
            }
        }

        /// <summary>Response text, falling back to a UTF-8 decode of the raw body when Text is empty.</summary>
        public static string BodyText(HttpResult res)
        {
            string text = res?.Text;
            if (string.IsNullOrEmpty(text) && res?.Body != null)
                text = Encoding.UTF8.GetString(res.Body);
            return text;
        }

        /// <summary>Cap a (possibly null) string at 500 chars for inclusion in an error message.</summary>
        public static string Truncate(string s)
        {
            if (string.IsNullOrEmpty(s)) return string.Empty;

View on GitHub (pinned to c21bf496bc)

Solutions

  1. Do NOT disable or bypass this check — it prevents API-key exfiltration.
  2. If the host change is legitimate (e.g. a new CDN), update the allowedHost passed to RequireHost for that call site to the new trusted host.
  3. If unexpected, investigate the upstream response that produced the off-host URL — it may indicate a compromised/MITM endpoint.
  4. Ensure the URL is absolute https and the host matches exactly (no trailing slash, correct subdomain).
Defensive patterns

Strategy: validation

Validate before calling

// Validate the host yourself before relying on a provider-supplied URL.
static bool IsTrustedHost(string url, string allowed)
    => Uri.TryCreate(url, UriKind.Absolute, out var u)
       && u.Scheme == Uri.UriSchemeHttps
       && string.Equals(u.Host, allowed, StringComparison.OrdinalIgnoreCase);

Type guard

static bool IsSafeCredentialUrl(string url, string allowedHost)
    => Uri.TryCreate(url, UriKind.Absolute, out var u)
       && u.Scheme == Uri.UriSchemeHttps
       && u.Host.Equals(allowedHost, StringComparison.OrdinalIgnoreCase);

Try / catch

// This is a security fail-fast — do NOT swallow silently. Investigate the source of the URL.
try { ProviderHttp.RequireHost(url, allowedHost, apiKey, ctx); }
catch (Exception) { McpLog.Error($"Blocked credential send to off-host URL: {url}"); throw; }

Prevention

When it happens

Trigger: A provider response embeds a download/redirect URL on a different domain than the expected provider host; a CDN host changed; an endpoint constant was edited to a wrong host; http (non-https) URL; a relative URL passed where absolute was expected.

Common situations: Sketchfab/Meshy moves its asset CDN to a new domain; a developer overrides an endpoint constant; a test stub returns a localhost URL; an attacker-influenced field reaches RequireHost.

Related errors


AI-assisted analysis of CoplayDev/unity-mcp@c21bf496bc (2026-08-13). Data as JSON: /api/errors/0fe2a1873dda80c5. Report an issue: GitHub.