Repository navigation
fix(migrate): require a per-run token and a known Host, and escape quotes in the review page - #696
Merged
Merged
Conversation
…otes in the review page The migration review server commits entity id changes with the operator's wiki credential and listens on every interface, but answered anyone: a machine on the network could pair and commit, and a web page open in the operator's browser could start a commit with a plain cross-site POST. - Refuse a request whose Host or Origin does not name this machine, the name the tool prints, or MIGRATE_ALLOWED_HOSTS. - Make a random token for each run. The printed address carries it once; the server swaps it for a SameSite=Strict HttpOnly cookie and redirects to a clean URL. Every other request needs the cookie. - The review page built HTML from park and wiki names and ids with an escape that left double quotes alone, then used the result inside quoted attributes. A name containing a quote could add an event handler, and the page can start a commit. Escape quotes, escape the fields that were not escaped at all, and move the row and progress templates into functions the tests can call. - Split startMigrationServer into createMigrationApp (no listen) and the listener so the access rules are testable. The default bind is unchanged. - Share the Host and Origin check with the web admin server. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Moving the Host and Origin check into its own function meant the CORS policy reflected any origin and relied on a check elsewhere. Validate in the origin callback as well so the policy stands on its own. Also match the script tag case-insensitively when the escaping test reads the review page. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…regex Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
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.
Summary
The migration review server (
npm run migrate -- <park>) commits entity id changes with the operator's wiki credential, and it listens on every interface so it can be reviewed from another machine. It answered anyone:POST /api/mappings/:ito pair and confirm, thenPOST /api/commit./api/commitignores its request body, so a plain cross-site POST from any page open in the operator's browser could start a commit. No preflight, no CORS needed.value="..." data-name="..."). A name containing a quote could add an event handler. The page is same-origin with the commit endpoint.MIGRATE_ALLOWED_HOSTS(comma separated hostnames, no ports) for opening the page by an address other thanMIGRATE_HOSTor the machine name. The 403 says so. Documented in the header ofsrc/tools/migrate/index.ts.esc()is now plain string work that also escapes"and'. The row and progress-line templates moved intorenderRowHtmlandrenderProgressLine, and the progress line (ids were unescaped) and the entity type now go throughesc().startMigrationServeris split intocreateMigrationApp(no listen) and the listener, so the access rules are testable. The default bind is unchanged.refuseForeignHostOrOrigin, shared by both servers.origin: true), so it no longer depends on the check running before it. Behaviour is unchanged.Evidence
POST /api/commitfrom any host or origin was served. After: the real startup code on a spare port, probed with curl:access.test.ts(token handshake, cookie flags, wrong token and cookie, foreign Host and Origin, a pairing change that must not apply without the cookie, no CORS headers) anduiEscaping.test.ts(the page script run in avmcontext; hostile names and ids go through the dropdown, row and progress-line builders).SameSite=Strict, cookie withoutHttpOnly,esc()keeping quotes, an unescaped progress id, an unescaped entity type.npm run typecheckis clean.Merge Danger
Door: two-way. Revert the commit.
Blast Radius: people who run
npm run migrate. Old bookmarked addresses stop working because the token changes every run: open the address the tool prints. Opening the page by an IP address or a name other thanMIGRATE_HOSTor the machine name needsMIGRATE_ALLOWED_HOSTS. The page script is covered by string-level tests, not a browser, so give the review page one look in a browser after merging.🤖 Generated with Claude Code