-
Notifications
You must be signed in to change notification settings - Fork 615
[BUG][SECURITY]: Log injection via unsanitized control characters in unauthenticated query parameters #3000
Copy link
Copy link
Labels
MUSTP1: Non-negotiable, critical requirements without which the product is non-functional or unsafeP1: Non-negotiable, critical requirements without which the product is non-functional or unsafebugSomething isn't workingSomething isn't workingpythonPython / backend development (FastAPI)Python / backend development (FastAPI)securityImproves securityImproves security
Milestone
Description
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 callbackerror/error_descriptionquery 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 detectedReactions are currently unavailable
Metadata
Metadata
Assignees
Labels
MUSTP1: Non-negotiable, critical requirements without which the product is non-functional or unsafeP1: Non-negotiable, critical requirements without which the product is non-functional or unsafebugSomething isn't workingSomething isn't workingpythonPython / backend development (FastAPI)Python / backend development (FastAPI)securityImproves securityImproves security