Bind mavweb to loopback and make the step-up fail-open loud and overridable
The /tools enable action takes name+cmd from form fields and calls
core.EnableTool, so it defines arbitrary argv that internal/tool then executes.
Its step-up gate read `session != nil && !session.IsStepUp()`, and
stepUpSession is nil unless both -webauthn-origin and -webauthn-rpid are set —
so with neither flag the gate was skipped entirely. compose passed neither and
published 9201 on every host interface, while /ptt proxies to the voice server
unauthenticated, so a caller could enable a tool, trigger it, and answer its
own confirm turn. internal/tool's boundary reasoning ("a compromised router
can't grant itself a capability") held; the outer boundary it depends on was an
unwritten deployment assumption.
The fail-open itself stays: gating on a session that can never be asserted
would 403 permanently, and that reasoning is sound. What was missing is the
compensating control.
- compose publishes 127.0.0.1:9201 so reaching the UI requires the wg tunnel by
construction rather than by convention. Verified no other service reaches
mavweb by host-published port; mavpoll is host-networked but only dials
netdata and kuma.
- stepUpOK() replaces the two inline gates in handleTools and handleRevert, so
one decision point covers both surfaces.
- -require-stepup (default false, behaviour byte-for-byte unchanged) fails those
actions closed when step-up cannot be asserted.
- A startup warning names both unguarded surfaces when stepUpSession is nil,
in fail-open and fail-closed variants.
Also repoints one doc comment at DESIGN.md, since it shared a hunk with the
warning block.
The committed kuma key is deliberately left for a separate change: the old
value is in git history forever, so rotation means a genuinely new key, not a
re-commit under a variable.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X5JApcrCRVGmqrxnhynSik
This commit is contained in:
+6
-1
@@ -82,7 +82,12 @@ services:
|
||||
command: ["mavweb", "-addr", ":9201", "-voice", "mavend:9100", "-core", "/run/maven/mavend.sock",
|
||||
"-nexus", "http://nexus:9740", "-praxis", "http://praxis:8989", "-hexis", "http://hexis:9741"]
|
||||
depends_on: [mavend]
|
||||
ports: ["9201:9201"]
|
||||
# loopback-only on purpose: /tools defines+executes arbitrary argv and
|
||||
# mavweb has no in-process auth of its own without -webauthn-origin/-rpid.
|
||||
# Reaching the UI therefore requires the wg tunnel (or the local nginx) by
|
||||
# construction, not by convention. The other daemons talk to mavweb over
|
||||
# the compose network, not this published port.
|
||||
ports: ["127.0.0.1:9201:9201"]
|
||||
# ecosystem: reach the siblings by name for the read-only /ecosystem panel;
|
||||
# default: keep resolving mavend:9100 for voice + the IPC socket peers.
|
||||
networks: [default, ecosystem]
|
||||
|
||||
Reference in New Issue
Block a user