Skip to content

docs(web): script the half of #648's secure-context check a shell can do - #748

Merged
eaitbrahim merged 1 commit into
mainfrom
feat-648-remote-exposure
Sep 7, 2026
Merged

docs(web): script the half of #648's secure-context check a shell can do#748
eaitbrahim merged 1 commit into
mainfrom
feat-648-remote-exposure

Conversation

@eaitbrahim

Copy link
Copy Markdown
Contributor

Partial for #648does not close it, and the reason is the point.

Four of #648's five items already shipped in #678 and #680. I mutation-tested all six defences rather than trusting they were covered — skipping the Host check, admitting a non-loopback name on a loopback bind, dropping the port check, accepting a wildcard external host, making the remote session immortal, removing the wildcard-bind guard — all six killed.

The fifth item, secure-context re-verification, needs a real deployed origin. This turns that from an open research question into a two-minute run.

Two parts, and the split is the honest shape of the requirement

Part 1 — what HTTP can answer. The shell served over the external origin; the token exchanged for a SameSite=Strict cookie there; manifest.webmanifest and sw.js actually served; nosniff present; and the one that matters most — a spoofed Host: still refused. --external-host teaches the server one name, and a deployment where Host: evil.example is answered is one where the allowlist has been widened until it stopped being one. Non-zero exit on any failure.

It refuses a plain http:// origin outright rather than warning: every check is about what HTTPS provides, and against http:// it would report a pass for a page that is not a secure context.

Part 2 — what only a browser can answer. window.isSecureContext, whether the worker registered and with what scope, whether the cache is genuinely per-origin, whether the manifest installs, and how the installed console behaves when the tunnel dies. Printed as a checklist and not covered by the exit code — a script claiming isSecureContext from curl would be reporting something it never looked at.

A test asserts part 1 makes no such claim, scoped to the executable region so the header comment may still name the property in order to say it cannot check it.

Why this doesn't close the issue

docs/remote-access.md keeps its ⛔ section and now points at the script. #648 closes when part 2 has been done on a device and recorded on the issue. Part 1 passing is not sufficient, and no amount of scripting makes it so.

The script joins the shellcheck suite, because a shell bug in it is a bug in the one check standing between an operator and an exposed financial surface.

Gates

6,297 passed / 3 skipped; ruff clean (the one E501 is pre-existing); shellcheck clean.

🤖 Generated with Claude Code

https://claude.ai/code/session_01KZZxmspQXe5qJ9FAsG13s6

… do, and say which half that is

#648's last open item is secure-context re-verification, and `docs/remote-access.md`
already records why it cannot be closed from a checkout: `http://127.0.0.1` is a
secure context BY SPECIFICATION, so the service worker and manifest work today
without anyone arranging it. Over an external origin that property comes from
HTTPS instead and has to be re-verified there.

This turns "needs a real origin" into a two-minute run once one exists.

TWO PARTS, AND THE SPLIT IS THE HONEST SHAPE OF THE REQUIREMENT

Part 1 is what HTTP can answer: the shell served over the external origin, the
token exchanged for a `SameSite=Strict` cookie there, `manifest.webmanifest` and
`sw.js` actually served, `nosniff` present, and -- the one that matters most --
A SPOOFED `Host:` STILL REFUSED. `--external-host` teaches the server one name,
and a deployment where `Host: evil.example` is answered is one where the
allowlist has been widened until it stopped being one. Non-zero exit on any
failure.

It refuses a plain `http://` origin outright rather than warning: every check in
it is about what HTTPS provides, and run against `http://` it would report a pass
for a page that is not a secure context.

Part 2 is what only a browser can answer -- `window.isSecureContext`, whether the
worker registered and with what scope, whether the cache is genuinely per-origin,
whether the manifest installs, and how the installed console behaves when the
tunnel dies. Printed as a checklist and NOT covered by the exit code. A script
claiming `isSecureContext` from `curl` would be reporting something it never
looked at, and a test asserts part 1 makes no such claim -- scoped to the
executable region, so the header comment may still name the property in order to
say it cannot check it.

WHAT WAS ALREADY DONE, VERIFIED RATHER THAN ASSUMED

Four of #648's five items shipped in #678 and #680. Rather than trust that, all
six defences were mutation-tested: skipping the Host check, admitting a
non-loopback name on a loopback bind, dropping the port check, accepting a
wildcard external host, making the remote session immortal, and removing the
wildcard-bind guard. All six killed.

The script joins the shellcheck suite, because a shell bug in it is a bug in the
one check standing between an operator and an exposed financial surface.

#648 does not close here. It closes when part 2 has been done on a device and
recorded on the issue.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KZZxmspQXe5qJ9FAsG13s6
@eaitbrahim
eaitbrahim merged commit 2411931 into main Sep 7, 2026
4 checks passed
@eaitbrahim
eaitbrahim deleted the feat-648-remote-exposure branch September 7, 2026 12:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant