Skip to content

[BUG][API]: admin_test_gateway crashes with ValueError on decode_auth of masked auth_value #3539

@crivetimihai

Description

@crivetimihai

Bug Description

The admin_test_gateway endpoint (POST /admin/gateways/test) crashes with a 500 Internal Server Error for all gateways — both those with authentication and those without.

Root Cause

mcpgateway/admin.py:12992 unconditionally calls decode_auth() on a masked GatewayRead object:

else:
    headers: dict = decode_auth(gateway.auth_value if gateway else None)

Problem 1: Masked value passed to decryption

get_first_gateway_by_url() (line 12945) returns a GatewayRead.masked() object where auth_value is the literal string "*****". decode_auth("*****") base64-decodes this to a 3-byte payload, then tries to extract a 12-byte nonce — producing:

ValueError: Nonce must be between 8 and 128 bytes

Problem 2: No auth_type guard

The else branch at line 12991 runs for ALL non-OAuth gateways — including those with auth_type=None. For gateways without auth, decode_auth(None) returns {} (harmless), but for gateways with auth, the masked value crashes.

Problem 3: ORM mutation from _prepare_gateway_for_read

get_first_gateway_by_url() calls the deprecated _prepare_gateway_for_read() which:

  1. Mutates the attached ORM object's auth_value from dict → encoded string
  2. Returns a .masked() GatewayRead where auth_value = "*****"

So the raw auth_value is never available to the caller.

Reproduction Steps

  1. Register any gateway (with or without auth)
  2. Open Admin UI → MCP Servers → click "Test" on any gateway
  3. Click "Test" in the connectivity dialog
  4. Observe 500 Internal Server Error
curl -X POST http://localhost:8080/admin/gateways/test \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"baseUrl": "http://fast_time_server:8080/sse", "method": "GET", "path": "/health", "headers": {}, "body": ""}'
# Returns: Internal Server Error

Stack Trace

File "/app/mcpgateway/admin.py", line 12992, in admin_test_gateway
    headers: dict = decode_auth(gateway.auth_value if gateway else None)
File "/app/mcpgateway/utils/services_auth.py", line 234, in decode_auth
    plaintext = aesgcm.decrypt(nonce, ciphertext, None)
ValueError: Nonce must be between 8 and 128 bytes

Suggested Fix

Option A — query raw DB object instead of masked GatewayRead:

# Use raw DB query instead of get_first_gateway_by_url (which masks)
raw_gateway = db.execute(select(DbGateway).where(DbGateway.url == validated_base_url)).scalars().first()
if raw_gateway and raw_gateway.auth_type in ("basic", "bearer", "authheaders"):
    if isinstance(raw_gateway.auth_value, dict):
        headers.update(raw_gateway.auth_value)
    elif isinstance(raw_gateway.auth_value, str):
        headers.update(decode_auth(raw_gateway.auth_value))

Option B — guard with auth_type check and handle masked sentinel:

if gateway and gateway.auth_type and gateway.auth_type != "oauth" and gateway.auth_value and gateway.auth_value != settings.masked_auth_value:
    headers.update(decode_auth(gateway.auth_value))

Impact

  • Severity: Medium — admin UI feature is completely broken for all gateways
  • Scope: Only the admin "Test Gateway Connectivity" button is affected
  • Security: No data exposure, but the 500 response leaks the error type in server logs

Metadata

Metadata

Assignees

Labels

apiREST API Related itembugSomething isn't workingpythonPython / backend development (FastAPI)securityImproves securitytriageIssues / Features awaiting triage

Type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions