fix: classify Tailscale CGNAT (100.64.0.0/10) as LAN, not public - #89
Open
PhilipEriksson wants to merge 1 commit into
Open
PhilipEriksson wants to merge 1 commit into
PhilipEriksson wants to merge 1 commit into
Conversation
classifyHostScope only recognized RFC1918 + loopback, so a spark whose
lanIp is a Tailscale 100.x address fell through to 'public'. Combined
with an unauthenticated LLM endpoint this produced a red 'Open · Public'
(danger) badge even though the address is only reachable inside the
tailnet. Treat 100.64.0.0/10 as LAN so the badge reflects reality
('Open · LAN', warn). Add unit tests for the CGNAT block and its edges.
PhilipEriksson
marked this pull request as ready for review
September 9, 2026 14:25
Author
|
Hi @MikeGibbsOnyx @MiaAI-Lab — small nudge. One-line fix + tests: Tailscale 100.64.0.0/10 addresses classify as "public", producing a false "Open · Public" danger badge. Verified live — badge flips to "Open · LAN". Happy to adjust if you'd rather handle CGNAT differently. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
A spark whose
lanIpis a Tailscale address (100.64.0.0/10) shows a red "Open · Public" (danger) LLM-posture badge, even though the endpoint is only reachable inside the tailnet.classifyHostScope()inserver/validate.jsonly recognizes loopback and the RFC1918 private ranges (10/8, 172.16/12, 192.168/16) plus link-local. Tailscale's CGNAT range is none of those, so any100.xaddress falls through to the finalreturn "public".The posture badge is
auth×scope:auth = open(the LLM API answers unauthenticated — no key configured)scope = public(the Tailscale IP misclassified)open+public→level = "danger"→ the red "Open · Public" badge. That's a false alarm: the 100.x address is not on the public internet, it's a private tailnet interface.Why it shouldn't show as "public" on Tailscale addresses
Tailscale assigns every node a stable IP from 100.64.0.0/10 (RFC 6598 shared-address space, the same CGNAT block carriers use). Traffic to that IP is only routable by peers in the same tailnet — it is never exposed to the public internet. Classifying it as "public" misrepresents the exposure and triggers the danger badge for a setup that is, in practice, as private as a LAN.
Fix
Treat 100.64.0.0/10 as
laninclassifyHostScope():A Tailscale-hosted spark now reports "Open · LAN" (warn) instead of "Open · Public" (danger) — accurate, since the endpoint is unauthenticated but confined to the tailnet.
Note: the "Open" part is intentionally unchanged. It still correctly reflects that the LLM API accepts unauthenticated requests; the fix only corrects the scope (network reachability), not the auth posture. If you want the badge to drop below "warn", set an API key on the endpoint and it becomes "API key · LAN".
Tests
Added a unit test in
server/collectors/__tests__/LlmProbe.posture.test.jscovering the CGNAT block and its edges:100.64.0.1,100.89.38.120,100.127.255.254→lan100.63.0.1,100.128.0.1(just outside the block) →publicAll 13 tests pass (
node --test server/collectors/__tests__/LlmProbe.posture.test.js).Verified in production
Applied the same one-line change to a live sparkDash install (v1.8.5,
node --watchauto-reload). A spark withlanIp: 100.89.38.120(Tailscale) flipped fromOpen · Public(danger) toOpen · LAN(warn) on the next probe cycle, confirmed via the live WebSocket snapshot.