Repository navigation
Tags: WordPress/browser-extension
Tags
Security: validate the origin of the popup's REST nonce probe (#118) ## Summary Fixes a cross-origin disclosure of the WordPress REST nonce, plus a same-tab navigation race in the same code path, in the popup's nonce resolution. Reported privately; a GitHub Security Advisory accompanies this release. Severity: High. ## The issues **1. Cross-origin redirect harvest** (`44a54e1`). When the active page exposed no REST nonce, `resolveNonceForTab` (`src/popup/lib/actions.js`) fell back to fetching `wp-admin/profile.php` with `credentials: 'include'` and `redirect: 'follow'`, then scraped the `wp_rest` nonce from the response without checking the final response origin. A page the victim opens the popup on could 302 that credentialed request to a WordPress install where the victim is a logged-in administrator; the extension followed it with the victim's cookies, harvested that origin's real nonce, and handed it to the content script on the attacker's origin (forwarded as an `X-WP-Nonce` header to the attacker's server). Fix: refuse to read a nonce from a response whose final origin left the base that was probed (an origin-only `res.url` gate, mirroring the fresh-detection gate). **2. Same-tab navigation race** (`d396efe`). The popup captures the active tab once, then awaits the nonce fetch before messaging the result back. If the tab navigated to another document during that gap, the message (keyed to the tab id) delivered the harvested nonce to whatever document then held the tab. Fix: bind the nonce to the origin it was read from; the receiving content document uses it only when that origin matches its own `location.origin`. ## Impact The disclosed secret is the REST nonce, not the session cookie, and a WordPress nonce is session-bound. But WordPress accepts `_wpnonce` as a request parameter and honors the `_method=POST` override on a top-level GET, which carries default `SameSite=Lax` auth cookies, so a privileged REST write such as administrator-account creation is credible for a logged-in single-site administrator. - Affected: all versions before 1.0.4 (the nonce probe was introduced in 0.8.0). - Patched: 1.0.4. ## Tests Red-first reproductions: `test/actions.mjs` [49] (redirect harvest) and [50] (navigation source-binding), `test/content-lifecycle.js` [46] (receiver drops a cross-document nonce). Full suite green, lint clean, `dist/` and the Safari mirror in sync. ## Also in this PR - Version bump to 1.0.4 (macOS build 5). - `3de0ddb`: doc/preview cleanup, no shipped-behavior change. A separate REST-helper `redirect: 'error'` hardening (defense in depth) is parked on `defer/rest-redirect-policy` and intentionally not included here.
Tests: state the [44] fallback coverage honestly The block drives the derivation helper and target synthesis with the real libs; it does not drive the React hook pipeline its comment implied. Wording corrected per review; true integration coverage is a possible follow-up. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
v1.0.1: version bump (#82) Version bump for the coordinated store launch. 1.0.1 supersedes 1.0.0 as the launch version: the approved Apple 1.0.0 build 1 predates the #76 QA pass and the #81 popup hardening, so it releases quietly as a safeguard while 1.0.1 (this content) ships everywhere as the announced version. Checklist: manifest.json, package.json, package-lock.json (npm install --package-lock-only), MARKETING_VERSION in four build configs, Safari Resources mirror re-synced. CURRENT_PROJECT_VERSION stays 2 (#80; build 2 was never uploaded). Full test suite passes locally. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Follow-up to #76: block-inspector precedence test, ROADMAP truth-up (#78 ) Lands the two follow-ups from the #76 review, plus one piece of local-tooling hygiene. ## Regression test for the precedence fix #76's change to `loadBlockInspectorPref` shipped with no coverage; the review verified empirically that reintroducing the exact bug the new guard prevents (explicit per-origin `false` falling through to a `_global` `true`) passed the whole suite. New content-lifecycle block [41] closes that: it stubs `WPDBlockInspector` on the harness context and asserts all four precedence outcomes through the real content script. The suite is now 286 assertions; the injected-regression check fails as intended with the new block in place. ## ROADMAP accuracy Store states an external contributor cannot see from the repo: - v0.11.x status now reads "readiness complete; CWS submission approved, publication pending" — the unlisted Chrome Web Store submission is approved but has not been published, so "shipped" overstated it. - The Safari row moves the App Store Connect record, listing assets, and the submitted 1.0.0 build into Done, with App Review outcome as the remaining gate; status is now "in review". The store-readiness checklist ticks the bundle-identifier rename (#72) and the publisher account to match. ## eslint ignore for build/ `build/` (gitignored since #75) holds the App Store archive and exported installer. The archived `.app` contains copies of the shipped bundles, so a local archive breaks `npm run lint` with ~175 errors on files that are not lintable source. Added to the eslint ignores alongside `safari-build/`. No runtime changes; `dist/` untouched. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
v1.0.0: version bump (#73) Version bump to 1.0.0, to be released first as the 1.0 release candidate (tagged v1.0.0-rc1, GitHub pre-release). Functionally identical to v0.11.2. The only change since is internal Apple App Store preparation: Safari bundle identifiers moved to org.wordpress.browserextension under the WordPress Foundation developer account (#72). Bump checklist: manifest.json, package.json, package-lock.json (npm install --package-lock-only), MARKETING_VERSION in four build configs, Safari Resources mirror re-synced. Full test suite passes locally. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
v0.11.2: version bump (#70) Release metadata bump for 0.11.2. ## In this release - Mobile Preview keeps one window per site: a repeat click reuses the open preview, navigating it to the requested page and focusing it; distinct sites keep distinct windows (#66, #67, #69). - Dev-dependency security updates: ws 7.5.11 (#64), websocket-driver 0.7.5 (#68). Lockfile only, no shipped-code impact. ## Bump checklist - manifest.json version - package.json version - package-lock.json (npm install --package-lock-only) - MARKETING_VERSION in the four Safari build configs - Safari Resources mirror re-synced (manifest picked up the new version) Full test suite passes locally; CI runs the clean-rebuild dist/mirror drift check. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
PreviousNext