Found by the security review in the 2026-07 maintenance pass (#1643). This one needs a product decision from Erik — no code change made.
The situation
DarlingWebHostService.DecideWebAuth (:540-547) returns Allow for any loopback remote before any token check, and both the class doc (:44-50) and the method justify it with: "the web surface is read-only."
Since Custom Views v2 that is no longer accurate. The surface now has:
DarlingWebEndpoints.cs:183 — POST (create)
:223 — PUT (update)
:267 — DELETE
:291 — compose/run (arbitrary composed query)
The MCP host went the other way on the identical question (DarlingMcpHostService.cs:508-509):
NO loopback exemption — in exposed mode even a local client must present the token; that IS the loopback guard against SSRF/sandboxed sockets.
So the two surfaces now diverge on the same reasoning, and the web side's stated basis no longer holds.
Failure scenario
Any local process on the Darling host — an unprivileged user account, SSRF'd code, a sandboxed process, a scheduled task — reaches http://127.0.0.1:5153 with no credential and can read the entire monitoring store and create, modify, or delete custom views.
This is distinct from the accepted "loopback MCP servers exist" pattern: here the loopback allow persists even while the host is LAN-exposed, and the surface mutates state.
The decision
- Narrow: require the token on loopback whenever
networkMode is true, mirroring MCP. Loopback-only installs (the default) are unaffected.
- Broader: gate only the four mutation routes behind the token, leaving reads tokenless on loopback.
- Accept as-is: single-operator box, treat local processes as trusted.
Either of the first two also needs the doc comments at :44-50 and :534-539 corrected — as written they tell the next reader no writes exist.
Related, lower severity (same file)
Access token and session cookie cross the LAN in cleartext once network mode is on: the login form is method='get' (:696-737), so the long-lived access token becomes a URL query parameter on every first login, and the session cookie sets Secure = false (:624-637). The CIDR allowlist is a routing control and does not stop passive capture on the allowed segment. The 302 token-strip (:434-439) protects browser history and Referer, but not the wire.
Minimum: switch the login form to method='post' so the token stays out of URLs and intermediate access logs, and log a Warning at network-mode startup naming the cleartext exposure. TLS termination (or a documented, checked reverse-proxy requirement) is the actual fix.
Found by the security review in the 2026-07 maintenance pass (#1643). This one needs a product decision from Erik — no code change made.
The situation
DarlingWebHostService.DecideWebAuth(:540-547) returnsAllowfor any loopback remote before any token check, and both the class doc (:44-50) and the method justify it with: "the web surface is read-only."Since Custom Views v2 that is no longer accurate. The surface now has:
DarlingWebEndpoints.cs:183— POST (create):223— PUT (update):267— DELETE:291— compose/run (arbitrary composed query)The MCP host went the other way on the identical question (
DarlingMcpHostService.cs:508-509):So the two surfaces now diverge on the same reasoning, and the web side's stated basis no longer holds.
Failure scenario
Any local process on the Darling host — an unprivileged user account, SSRF'd code, a sandboxed process, a scheduled task — reaches
http://127.0.0.1:5153with no credential and can read the entire monitoring store and create, modify, or delete custom views.This is distinct from the accepted "loopback MCP servers exist" pattern: here the loopback allow persists even while the host is LAN-exposed, and the surface mutates state.
The decision
networkModeis true, mirroring MCP. Loopback-only installs (the default) are unaffected.Either of the first two also needs the doc comments at
:44-50and:534-539corrected — as written they tell the next reader no writes exist.Related, lower severity (same file)
Access token and session cookie cross the LAN in cleartext once network mode is on: the login form is
method='get'(:696-737), so the long-lived access token becomes a URL query parameter on every first login, and the session cookie setsSecure = false(:624-637). The CIDR allowlist is a routing control and does not stop passive capture on the allowed segment. The 302 token-strip (:434-439) protects browser history and Referer, but not the wire.Minimum: switch the login form to
method='post'so the token stays out of URLs and intermediate access logs, and log a Warning at network-mode startup naming the cleartext exposure. TLS termination (or a documented, checked reverse-proxy requirement) is the actual fix.