fix(connection): hold markerless requests to the Host fence — plain-HTTP browser reads carry no markers

Fetch-Metadata and Origin are only attached to trustworthy destinations, so
over plain HTTP a rebound page's same-origin GET (EventSource, images,
navigations) arrives with no browser markers and a readable response. Remove
the marker shortcut; non-browser clients pass the same fence via loopback,
the CLI-derived LAN IP literals, or a declared authority.
This commit is contained in:
creatixchu
2026-07-28 17:02:39 +08:00
parent 7ff8da56df
commit 772653464d
11 changed files with 45 additions and 41 deletions
@@ -8,13 +8,15 @@ function request(headers: Record<string, string | undefined>): { headers: Record
}
describe('isTrustedApiRequest', () => {
it('accepts every request without browser markers — curl, tests, native clients, on any Host', () => {
// No Origin and no sec-fetch-site → the sender is the principal itself
// (it forges Host freely anyway); this is the LAN-serving shape a Host
// fence must not break.
for (const host of ['127.0.0.1:3080', '192.168.1.5:3080', 'harness.example', undefined]) {
expect(isTrustedApiRequest(request(host === undefined ? {} : { host }), [])).toBe(true)
}
it('holds markerless requests to the same Host fence — a plain-HTTP browser read carries no markers', () => {
// Over plain HTTP a browser attaches neither Origin nor Fetch-Metadata to
// reads (EventSource, images, navigations), so a rebound-origin GET is
// markerless and its response readable: no marker shortcut may exist.
expect(isTrustedApiRequest(request({ host: '127.0.0.1:3080' }), [])).toBe(true)
expect(isTrustedApiRequest(request({ host: '192.168.1.5:3080' }), ['192.168.1.5'])).toBe(true)
expect(isTrustedApiRequest(request({ host: '192.168.1.5:3080' }), [])).toBe(false)
expect(isTrustedApiRequest(request({ host: 'harness.example' }), [])).toBe(false)
expect(isTrustedApiRequest(request({}), [])).toBe(false)
})
it('accepts loopback Hosts in every spelling, with and without ports, for browser requests', () => {