M6 hardening: /recheck binds 0.0.0.0 (unauthenticated re-run trigger) #8

Closed
opened 2026-09-10 15:30:27 +00:00 by jmz · 1 comment
Owner

M5 whole-branch review (v0.17.0) minor, non-blocking hardening finding.

roles.run_role serves the new node POST /recheck on settings.http_bind, which defaults to 0.0.0.0 (config.py:176). /recheck is an unauthenticated POST that forces the node to re-run and re-publish its own checks. On an untrusted/reachable network this is a mild bus/CPU amplification (DoS) vector.

Fail-closed is intact: an attacker cannot fake an OK (the detector runs for real), so this cannot cause a false resolution. It is consistent with the current mesh trust posture (/health already binds 0.0.0.0; NATS auth/TLS explicitly deferred to M6). The orchestrator-driven path is loopback (the warden.caps.recheck helper POSTs to 127.0.0.1).

Fix (M6): bind /recheck to loopback (or gate it), and reconcile the doc/impl asymmetry: the caps-helper docstring says the client is 'always loopback' while the server binds broadly.

Found by the M5 whole-branch review; deferred as non-blocking.

M5 whole-branch review (v0.17.0) minor, non-blocking hardening finding. `roles.run_role` serves the new node `POST /recheck` on `settings.http_bind`, which defaults to `0.0.0.0` (config.py:176). `/recheck` is an unauthenticated POST that forces the node to re-run and re-publish its own checks. On an untrusted/reachable network this is a mild bus/CPU amplification (DoS) vector. Fail-closed is intact: an attacker cannot fake an OK (the detector runs for real), so this cannot cause a false resolution. It is consistent with the current mesh trust posture (`/health` already binds 0.0.0.0; NATS auth/TLS explicitly deferred to M6). The orchestrator-driven path is loopback (the warden.caps.recheck helper POSTs to 127.0.0.1). Fix (M6): bind /recheck to loopback (or gate it), and reconcile the doc/impl asymmetry: the caps-helper docstring says the client is 'always loopback' while the server binds broadly. Found by the M5 whole-branch review; deferred as non-blocking.
Author
Owner

Fixed in v0.18.0 (commits 66d6d81 + 23e50d6). POST /recheck is now gated to loopback callers (403 off-box, nothing published/run), reading the real TCP peer (self.client_address, not a spoofable header); /health unchanged. The caps-helper docstring is reconciled. Follow-up fix 23e50d6 makes IPv4-mapped loopback (::ffff:127.0.0.1) recognition correct on Python >=3.10 (not just 3.13+).

Fixed in v0.18.0 (commits 66d6d81 + 23e50d6). `POST /recheck` is now gated to loopback callers (403 off-box, nothing published/run), reading the real TCP peer (self.client_address, not a spoofable header); /health unchanged. The caps-helper docstring is reconciled. Follow-up fix 23e50d6 makes IPv4-mapped loopback (::ffff:127.0.0.1) recognition correct on Python >=3.10 (not just 3.13+).
jmz closed this issue 2026-09-10 16:17:44 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
public/warden#8
No description provided.