Files
Maciej Lisiewski 6c025ab898 fix(plugins): pin liveness endpoint URL to loopback (salvage #125745) (#155387)
* fix(plugins): pin liveness endpoint URL to loopback, harden manifest liveness parsing

A manifest's liveness.endpoint_path was concatenated verbatim onto the
loopback URL read from the app's runtime server.json and re-parsed by the
probe, so a crafted tail like '@attacker.example/' rewrote the URL authority
and the initialize request carried the runtime file's bearer token to a
manifest-chosen host.

Now the declaration parser only admits a plain path charset (no '@', '?',
'#', whitespace, scheme, or '..' segments), the resolver re-parses the fully
composed URL and requires it to stay on a loopback host with the same port
and no userinfo, and _mcp_initialize re-verifies scheme/host/port before the
socket opens so the transport-facing endpoint() path is covered too.

Adjacent hardening in the same surface: liveness.path must be a rooted
filesystem path in both parse surfaces, server.json key overrides must be
simple key names, malformed pids (bool, >int32) degrade instead of crashing
os.kill, a non-mapping 'fields' value raises ValueError inside the fail-closed
contract instead of TypeError, and a manifest whose liveness fails validation
renders 'unknown' on the catalog card instead of 'present'.

* test(plugins): satisfy ruff PLR0402 in salvaged liveness test

Follow-up to the salvaged #125745 commit after rebasing onto main.

Refs #125744

* test(plugins): build hostile-endpoint fixture with a valid AppLocation tuple

AppDef.locations is tuple[AppLocation, ...]; the fixture passed a bare
string, which only worked because endpoint() never reads locations.

Refs #125744

---------

Co-authored-by: beardthelion <beardthelion@users.noreply.github.com>
6c025ab898 · 2026-11-14 12:46:07 +01:00
History
..
…