Skip to content

[BUG][SECURITY]: Log injection via unsanitized control characters in unauthenticated query parameters #3000

@crivetimihai

Description

@crivetimihai

Description

Several log statements interpolate values from unauthenticated HTTP query parameters directly into log messages without stripping control characters. A %0A (newline) in a query parameter is URL-decoded by the ASGI framework and passed through to Python's logging module, which does not sanitize newlines. This allows an attacker to inject fabricated log lines.

Example in mcpgateway/routers/oauth_router.py:294:

logger.warning(f"OAuth provider returned error callback: error={error}, description={error_description}")

A request like:

GET /oauth/callback?state=x&error=foo&error_description=bar%0ACRITICAL:root:SECURITY+BREACH

produces two log lines, the second entirely fabricated.

Impact

  • Low severity: no authentication bypass or data exposure
  • Affects log-based SIEM alerting and forensic analysis (fabricated log entries)
  • Mitigated by structured logging (JSON format) which encapsulates the full message as a single field

Suggested Fix

Introduce a utility that strips \n, \r, and other control characters from values before logging, and apply it at all locations that log unauthenticated input. Alternatively, enable structured (JSON) logging globally which inherently prevents line injection.

Affected Areas

  • mcpgateway/routers/oauth_router.py — OAuth callback error / error_description query params
  • Potentially other routers that log path/query parameters from unauthenticated endpoints

Reproduction

import logging, io

handler = logging.StreamHandler(stream := io.StringIO())
handler.setFormatter(logging.Formatter('%(levelname)s:%(name)s:%(message)s'))
logger = logging.getLogger('test')
logger.addHandler(handler)
logger.setLevel(logging.DEBUG)

# Simulates URL-decoded %0A in error_description
error_description = "bad scope\nCRITICAL:root:SECURITY BREACH detected"
logger.warning(f"OAuth error: {error_description}")

print(stream.getvalue())
# WARNING:test:OAuth error: bad scope
# CRITICAL:root:SECURITY BREACH detected

Metadata

Metadata

Assignees

Labels

MUSTP1: Non-negotiable, critical requirements without which the product is non-functional or unsafebugSomething isn't workingpythonPython / backend development (FastAPI)securityImproves security

Type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions