pypi chainlit 2.12.0

5 hours ago

⚠️ Security release — breaking changes, action required if you use MCP

This release fixes two vulnerabilities in the /mcp endpoint, both exploitable by an unauthenticated attacker whenever features.mcp.enabled = true.

CVE Advisory CVSS v3.1 Severity Issue
CVE-2026-45018 SPL-2026-001 9.8 Critical Command injection via the MCP stdio transport
CVE-2026-45019 SPL-2026-002 7.2 High SSRF via the MCP streamable-http / SSE transports

Affected: v2.4.0rc0 – v2.11.x. MCP has been disabled by default since v2.7.0, which limits real-world exposure — if you never set features.mcp.enabled = true, you were not vulnerable.

If you cannot upgrade immediately, set features.mcp.enabled = false (the default). This fully prevents exploitation of both issues.

📄 Full technical detail, impact analysis and mitigations: docs/security-advisory-2026-mcp.md

The fix for the command injection is architectural rather than filtering — no argument-level validation can sandbox a command whose full argument list the attacker controls. fullCommand is removed from the client request entirely: stdio servers are now declared only in server-side config, and the client sends just a name.


🔧 Migration guide

1. MCP config (.chainlit/config.toml)

Legacy MCP keys now abort startup instead of being silently ignored. If your config contains [features.mcp.sse], [features.mcp.stdio], [features.mcp.streamable-http] or allowed_executables, the app will refuse to start until you migrate.

Before (v2.11.x):

[features.mcp]
enabled = true

[features.mcp.stdio]
enabled = true
allowed_executables = ["npx", "uvx"]

[features.mcp.sse]
enabled = true
allowed_urls = ["https://mcp.example.com"]

After (v2.12.0):

[features.mcp]
enabled = true

# Developer-configured servers (replaces allowed_executables / allowed_urls)
[[features.mcp.servers]]
name = "github"
type = "stdio"
command = "npx -y @modelcontextprotocol/server-github"

[[features.mcp.servers]]
name = "my-sse"
type = "sse"
url = "https://mcp.example.com/sse"

# Optional: allow end-users to connect their own SSE/HTTP servers
[features.mcp.user_servers]
enabled = true
allowed_urls = ["https://mcp.example.com"]

Additional notes:

  • Inline KEY=value assignments must move to an env mapping on the server entry.
  • Redirects are no longer followed. If an allowed_urls entry or a server url relied on an httphttps upgrade redirect, configure the final https:// URL directly.
  • URLs must not contain ./.. segments, encoded separators (%2e, %2f, %5c), double-encoded sequences (%25), backslashes, or non-ASCII characters.
  • A user_servers connection's name cannot match (case-insensitively, ignoring surrounding whitespace) the name of any server in [[features.mcp.servers]].

2. @chainlit/react-client 0.5.0

Before (v2.11.x) After (v2.12.0)
connectStdioMCP(sessionId, name, fullCommand) Removed, no replacement — see below
connectSseMCP(sessionId, name, url, headers?) connectUserMcp(sessionId, name, 'sse', url, headers?)
connectStreamableHttpMCP(sessionId, name, url, headers?) connectUserMcp(sessionId, name, 'streamable-http', url, headers?)
(n/a) connectMcp(sessionId, name) — connects any named server

connectStdioMCP is removed with no replacement: accepting a client-supplied command was CVE-2026-45018. Declare stdio servers in [[features.mcp.servers]] and connect by name with connectMcp(sessionId, name).

IMcp also changed: clientType is now optional and narrowed to 'sse' | 'streamable-http', type was added for named servers, command was removed, and isUserProvided was added — check that flag directly rather than inferring from the presence of url or clientType.

IChainlitConfig.features.mcp changed to match: the per-transport sse / streamable_http / stdio flag objects are replaced by servers?: Array<{ name, type }> and user_servers?: { enabled?: boolean }.


⚠️ Breaking changes

  • Legacy MCP config keys ([features.mcp.sse], [features.mcp.stdio], [features.mcp.streamable-http], allowed_executables) abort startup when MCP is enabled instead of being silently ignored; they are replaced by a unified [[features.mcp.servers]] array and an optional [features.mcp.user_servers] section
  • stdio MCP servers must be declared in [[features.mcp.servers]] with type = "stdio" and a command — a client-supplied fullCommand is rejected, and inline KEY=value assignments must move to an env mapping on the server entry
  • type is now required on every [[features.mcp.servers]] entry — StdioMcpServer, SseMcpServer and StreamableHttpMcpServer no longer default it, so servers constructed in Python must pass it explicitly
  • User-provided SSE/HTTP connections require an explicit [features.mcp.user_servers] enabled = true and a non-empty allowed_urls, where they were previously enabled by default
  • MCP connections no longer follow HTTP redirects, for developer-configured servers as well as user-provided ones — configure the final https:// URL directly
  • User-provided MCP connections are re-checked against their allowlist entry on every request rather than only the first
  • Duplicate, empty and colliding MCP server names are rejected instead of loading silently
  • /mcp returns isUserProvided instead of url/headers for developer-configured (named) servers
  • @chainlit/react-client 0.5.0 removes connectStdioMCP(), connectSseMCP() and connectStreamableHttpMCP() — use connectMcp() for named servers and connectUserMcp() for user-provided ones

Security

  • Fix critical command injection (CVE-2026-45018, SPL-2026-001) and SSRF (CVE-2026-45019, SPL-2026-002) in the /mcp endpoint — stdio MCP servers are now defined server-side and the client supplies only a name
  • Filter Cookie, Host, Forwarded, X-Forwarded-*, X-Real-IP, Via, Proxy-Authorization and the method/URL override headers from user-provided MCP connections
  • Stop disclosing the user_servers allowlist and server details through /project/settings
  • Reject MCP URLs containing ./.. segments, encoded separators, double-encoded sequences, backslashes or non-ASCII characters
  • Raise backend minimum versions for mcp, pydantic, pydantic-settings, pyjwt and python-multipart, and pin more than thirty vulnerable JS dependencies — including lodash, postcss, micromatch, form-data, undici, ws and rollup — to patched ranges across all four workspaces
  • Upgrade react-router-dom to 6.30.6, clearing an open-redirect to XSS advisory that covered every previously shipped 6.30.x
  • Upgrade socket.io-client to 4.8.3 in the published @chainlit/react-client, moving its engine.io-client/ws chain onto patched versions — the one dependency change here that reaches downstream npm consumers

Added

  • Add a localized tooltip to the settings icon
  • Add SECURITY.md with a responsible disclosure policy
  • Support single-tenant Azure Bot registrations for Teams via TEAMS_APP_TENANT_ID

Fixed

  • Bound the MCP connect handshake so a blocked destination fails fast instead of hanging and leaking its connection task
  • Keep the existing MCP session until a reconnect has succeeded, so a failed reconnect no longer drops a working connection
  • Serialise concurrent reconnects to the same MCP server name to avoid leaking a live connection
  • Report the underlying cause of an MCP connect failure instead of an empty error
  • Drop malformed stored MCP entries instead of letting them break the chat page
  • Resolve MCP servers declared in a chat profile's config_overrides instead of returning a 500 from /project/settings
  • Redirect OAuth login failures to the login page with a friendly error instead of raw JSON or a bare 500
  • Render file elements with a null mime instead of crashing the thread view
  • Reconstruct uploaded PDFs as Pdf elements in Element.from_dict
  • Handle a missing userEnv payload on WebSocket connect
  • Validate DatePicker mode and min_date/max_date bounds
  • Scope cache entries by function identity so same-named callables no longer return each other's values
  • Degrade emoji markers in lint-translations instead of raising UnicodeEncodeError on legacy consoles
  • Expose the OAuth2 model on OAuth2PasswordBearerWithCookie so OpenAPI generation no longer raises
  • Resolve the transparent Copilot UI in light mode

Other changes

  • Declare pydantic>=2.11.0 explicitly, narrowing the installable range from >=2.7.2; this was already required transitively by mcp>=1.28.1, so no install that resolves today stops resolving
  • Drop the unused audioop-lts core dependency

🙏 Credit

CVE-2026-45018 and CVE-2026-45019 were reported by Vipin and Stephen at SPL Security (security@spl.team) under coordinated disclosure, with working proof-of-concept exploits for both issues. We thank them for a thorough and responsibly disclosed report.


Merged pull requests

  • feat: add missing tooltip to settings icon by @eiseleMichael in #2903
  • docs: add SECURITY.md with responsible disclosure policy by @dokterbob in #2900
  • fix(teams): support single-tenant bots via TEAMS_APP_TENANT_ID env var by @xodn348 in #2928
  • fix(socket): handle missing user env by @pragnyanramtha in #2927
  • ci: install Cypress binary before e2e tests by @lntutor in #2989
  • fix(elements): render file elements with null mime instead of crashing by @mihidumh in #2939
  • fix(settings): validate DatePicker mode and bounds by @lntutor in #2988
  • Fix: Resolve transparent UI issue in Copilot Light Mode by @taeminlee in #2977
  • fix(elements): reconstruct uploaded PDFs as Pdf elements in Element.from_dict by @lntutor in #2984
  • chore(deps): drop unused audioop-lts core dependency by @lukehsiao in #2980
  • fix(cache): scope entries by function identity by @lntutor in #2987
  • fix(cli): avoid lint-translations UnicodeEncodeError on legacy consoles by @lntutor in #3006
  • fix(auth): expose cookie OAuth model for OpenAPI by @gaoflow in #2968
  • fix(deps): bump lodash to 4.18.1 for prototype pollution fix by @EyalAmitay in #3012
  • fix(auth): redirect OAuth login failures to login page instead of raw JSON (#1273) by @dokterbob in #2955
  • chore(deps): upgrade dependencies with known vulnerabilities by @dokterbob in #2999
  • fix(mcp)!: prevent unauthenticated RCE and SSRF via /mcp (CVE-2026-45018, CVE-2026-45019) — reported by SPL Security, fixed under coordinated disclosure

New Contributors

Full Changelog: 2.11.1...2.12.0

@chainlit/react-client 0.5.0 is released alongside this version.

Don't miss a new chainlit release

NewReleases is sending notifications on new releases.