Portless
Portless security boundaries: loopback, forwarding headers and hosts-sync authorization
Understand local and public exposure, why forwarded headers are not trusted identity, and how the pinned internal hosts-sync endpoint authenticates requests.
What you will learn
- Local-only, LAN and public sharing are different scopes
- The internal endpoint has more than a loopback check
- Use the result without turning it into a security certification
Before you start
- Basic HTTP origins, ports and command-line concepts
- Ability to distinguish loopback, LAN and public exposure
Trace a named request, choose explicit setup boundaries and separate observed behavior from untested integrations.
Key takeaways
- Loopback, LAN, tailnet and public tunnels require separate exposure decisions.
- Preserved forwarding headers are not a sanitized security identity.
- A bounded authorization probe is not a complete security audit.
Local-only, LAN and public sharing are different scopes
The documented default proxy binds loopback. LAN mode changes listeners and advertises .local names; optional Tailscale sharing, Funnel and ngrok have different reachability and external dependencies. In particular, a public tunnel is not equivalent to a private local route. Inspect remembered LAN settings and sharing environment variables before exposing a development app containing debug endpoints or sample credentials.
The inspected proxy preserves supplied X-Forwarded-Proto, Host and Port values when present, and appends the peer address to X-Forwarded-For. Our fixture confirmed that behavior. Therefore those headers are not a cleaned identity assertion from a trusted public edge. An application must have an explicit trusted-proxy policy before using them for authorization, security redirects or client identity.
The internal endpoint has more than a loopback check
POST /.portless/hosts-sync is intercepted only for a literal loopback authority. The handler checks the actual peer, rejects Origin and Sec-Fetch-Site headers, requires exactly one correctly formatted token header and compares it with the configured token using timingSafeEqual. Missing credentials returned 401 in the probe; valid fixture credentials reached a harmless callback spy, not an operating-system writer.
The callback distinguishes an active sync from a disabled one, producing 204 or 409 respectively. Requests to the same path under an application hostname still reach the application. HEAD / can return an HMAC challenge proof only under its restricted conditions, and the proof can accompany a 404 response; daemon identity is not established by checking for HTTP 200 alone.
Use the result without turning it into a security certification
The probe rejected duplicate token headers and browser-origin metadata even with an otherwise valid fixture token. It also checked missing or invalid challenge proofs. This is evidence for the inspected branches, not a penetration test of DNS rebinding, all network peers, certificate storage, OS services or tunnel integrations. Never publish a real machine token in a diagnostic report.
Operational permissions remain important outside the HTTP handler. Route replacement with force can terminate a recorded process, certificate trust changes the machine trust boundary, and service installation may create privileged persistent execution. Review each action independently. The hop counter detects accidental forwarding loops, but a client-controlled header is not an authentication or denial-of-service protection system.
Implementation steps
- 1
Inspect effective binding and sharing settings before launch.
- 2
Define which proxy, if any, the application trusts.
- 3
Test internal authorization with fake tokens and a non-writing callback.
- 4
Keep force replacement, trust changes and service installation behind explicit approval.
Copy-ready example
{
"loopbackFixtureResults": {
"missingToken": 401,
"validTokenWithOrigin": 401,
"duplicateTokenHeaders": 401,
"validTokenSpyCallback": 204,
"disabledCallback": 409,
"validHeadProofStatus": 404
},
"hostsFileModified": false,
"realTokensUsed": false
}Frequently asked questions
Why can a valid challenge proof arrive with 404?
The proof header is added before normal routing continues. The literal loopback host need not have an application route, so its ordinary response can still be 404.
Does passing the token tests prove safe public deployment?
No. The tests cover selected loopback HTTP branches only. Public exposure, application authentication and other integration threats remain separate work.
Sources
- packages/portless/src/proxy.tsSource checked 2026-09-08
- packages/portless/src/hosts-sync-auth.tsSource checked 2026-09-08
- packages/portless/src/routes.tsSource checked 2026-09-08
- README.mdSource checked 2026-09-08