The Disclosure
This recasts the case study as a technical disclosure. This webpage and its verbatim description are copyrighted, but the systems described here are not officially patented. The Gizmo AI Unlimited extension is Copyright (c) 2026 Alexey Fedorov, All Rights Reserved, and is free for noncommercial use. Play Origin is licensed under the MPL 2.0.
Field
Methods and systems for modifying the runtime behavior of a third-party single-page web application, on the end-user's device, by substituting a transformed JavaScript bundle for the application's original bundle, while remaining within the execution constraints of a Manifest-V3 browser extension, and for keeping that transformation current as the third-party application is redeployed.
Background
Single-page web applications enforce business logic (entitlements, limits, gating) inside large minified JavaScript bundles delivered to the browser. Modifying that behavior on the client is obstructed by four compounding constraints.
First, bundle minification and frequent redeployment: variable names and file hashes change on every vendor deploy, meaning any patch keyed to literal identifiers rots within days. Second, Manifest V3 (MV3): extensions may not eval() remote code or inject arbitrary <script src> of remote origin into a page the way MV2 allowed; the classic "rewrite the page script" approaches are gone. Third, Subresource Integrity (SRI): the vendor's <script integrity="sha384-…"> causes the browser to reject any substituted bytes. Fourth, Content-Security-Policy (CSP): the page may forbid inline scripts and eval, blocking naive injection.
Existing approaches (MV2 webRequest rewriting, static forks, eval-based loaders) are foreclosed or brittle under these constraints.
Summary
A two-subsystem system is disclosed.
A derivation subsystem ("patcher") executes on a schedule in a trusted automation environment. It fetches the third-party application's current bundle (defeating bot heuristics with a realistic User-Agent), applies an ordered set of anchored regular-expression transformation rules, verifies each rule meets a minimum match count, and publishes either (i) the transformed bundle (file-pull model) or (ii) a compact, content-hashed rule manifest plus optional runtime wrapper (rules model), to a content-distribution endpoint.
An application subsystem ("extension") executes in the end-user's MV3 browser. It (1) blocks the original bundle via declarative network rules; (2) neutralizes integrity attributes and intercepts every DOM path by which the original script could load (prototype method overrides, mutation observation, and preload removal); (3) obtains the transformed JavaScript, either by downloading it directly (file-pull) or by downloading the rule manifest and the pristine bundle and applying the rules locally in a background service worker, caching the result keyed by a tuple of {bundle identifier, rule-set hash} (rules model); and (4) injects the transformed JavaScript into the page's own JavaScript realm by writing it to an HTML event-handler content attribute and dispatching a synthetic event, with a scope-chain compensation that rebinds shadowed globals.
The system self-heals: scheduled re-derivation republishes within a bounded interval after any third-party redeployment, restoring function without an extension update (rules model) or with only a data-file change (file-pull model).
Detailed embodiments
The derivation subsystem
Probe and anti-bot: The patcher fetches a deep application URL (not the root, which may redirect to authentication) with a browser-realistic User-Agent header to obtain genuine markup rather than a bot-challenge stub. Gizmo uses a specific quiz URL; P-NP fetches math.prodigygame.com/load and parses a JSON field for the game client version.
Locate: A regex extracts the versioned bundle URL from the response HTML, for example entry-<hash>.js or code/<version>/game.min.js. The URL changes on every vendor redeploy; capturing it from live markup is what makes the pipeline version-agnostic.
Transform: Ordered rules of the form { id, find, flags, replace, minMatches } are applied to the pristine bundle. Three embodiment variants appear in the shipped systems: (a) replacing an entitlement-check sub-expression with the context-neutral truthy primary expression (!0), which stays grammatically valid in every surrounding context a minifier produces (ternary operand, || operand, ! operand, bare assignment), whereas a naive ||!0 appended to a ??-laden expression forms the illegal ||…?? mix and bricks the bundle; (b) capture-group back-reference substitution ($1…$n) for structural rewrites that must preserve surrounding tokens; (c) prepended or wrapped injection points that install hooks at located anchors.
Verify and gate: Match counts are accumulated per rule. In the fail-closed embodiment (Gizmo), any rule below minMatches causes a throw: the pipeline refuses to write output, the CI job fails, a deduplicated GitHub issue is opened, and the last-known-good artifact remains in place so users keep working until a human re-anchors the regex. In the fail-open embodiment (P-NP), under-matching sets a patchDegraded flag in the telemetry artifact but publication proceeds; only a hard failure (network error, non-JS response) throws.
Hash and publish: A content hash is computed over the canonicalized rule set (and wrapper, where present). The primary artifact is published without a per-run timestamp, making it byte-stable across no-op runs, a property the client's cache-invalidation scheme depends on. A separate timestamped telemetry artifact records per-run metadata. The CI commit step stages only the stable artifacts first; if the diff is empty it exits without a commit, so the repository only records a commit when substance changes.
Schedule: Both patchers run on cron: "0 */2 * * *" (every two hours) and on workflow_dispatch for manual triggers, with concurrency: cancel-in-progress: false to serialize runs and a 30-second per-fetch AbortController timeout.
The application subsystem
Network block: A declarativeNetRequest BLOCK rule is registered on the bundle URL pattern, for example *://app.gizmo.ai/_expo/static/js/web/entry-*.js. The pattern uses leading scheme wildcards and bare path wildcards without requiring the more constrained regexFilter form. A critical property: the extension's own service-worker fetch() is not subject to that extension's own DNR rules, so the background worker can still retrieve the pristine bundle from the vendor even though the page is forbidden from loading it. An extended embodiment (Play Origin) additionally uses DNR MODIFY_HEADERS to strip Content-Security-Policy and X-Frame-Options, plus cosmetic REDIRECT rules.
Integrity neutralization: Before any vendor script can register an integrity attribute, a MAIN-world content script redefines the integrity accessor on HTMLScriptElement.prototype and HTMLLinkElement.prototype to a no-op getter/setter, overrides Document.prototype.createElement to lock integrity on new nodes, drops integrity in setAttribute, and strips it from any node observed by the MutationObserver.
Universal interception: Node.prototype.appendChild, Node.prototype.insertBefore, and Element.prototype.append are wrapped: if the inserted node is the target script, it is replaced with an inert "nop" script and injection is triggered. A MutationObserver catches parser-inserted <script> elements (which bypass prototype overrides), neutralizes their src/textContent, and triggers injection. Matching <link rel="preload"> elements are removed so the browser wastes no request on the blocked URL. An early scanExistingDom() call handles the race where the script is already present when the content script initializes. The original URL is captured at interception and threaded through to the patch request.
Privilege bridge: The injection and DOM overrides run in the page's JS realm (MAIN world), which has no access to chrome.*. The cache and privileged fetch live in the background service worker, reachable only from an ISOLATED-world content script. The two contexts share the DOM and relay via CustomEvent on document:
- MAIN dispatches
__gizmo_patch_request__carrying the original URL - ISOLATED receives it and calls
chrome.runtime.sendMessage("GET_PATCHED_BUNDLE") - background fetches, applies, caches, and returns the patched JS
- ISOLATED dispatches
__gizmo_patch_response__back to MAIN
A registration-order subtlety: both content scripts run at document_start, but the ISOLATED bridge registers its listener synchronously at top of file, while MAIN only dispatches after detecting a script, which guarantees the listener is always ready first. An alternative embodiment (Play Origin) relays via data-origin-* DOM attributes and a data-origin-ready handshake instead of request/response events.
Obtain transformed code: In the file-pull model, the background (or MAIN directly in simple configurations) fetches the published transformed bundle from the content-distribution endpoint. In the rules model, the background worker: (1) fetches patches.json (browser HTTP cache permitted); (2) checks chrome.storage.local for a cache entry keyed by { bundleFilename, patchesHash }; (3) on a hit returns the stored patched bundle; (4) on a miss, fetches the pristine bundle from the vendor, applies the rules, wraps with markers, stores to cache, and returns.
Realm injection: The transformed code is injected into the page's JS realm via the onreset trick:
const payload = "var URL=window.URL;\n" + js;
document.documentElement.setAttribute("onreset", payload);
document.documentElement.dispatchEvent(new CustomEvent("reset"));
document.documentElement.removeAttribute("onreset");An HTML event-handler content attribute is compiled by the browser into a function and executed in the page's own JavaScript realm when its event fires. This executes the bundle string synchronously, without extension-side eval, without inserting a <script> element. The var URL=window.URL; prefix is required because event-handler content attributes run with the element and document on the scope chain (the legacy with(document) semantics), which would otherwise shadow the global URL constructor with document.URL (a string), causing new URL(...) calls inside the bundle to throw a TypeError on boot. reset is chosen because it is benign and nothing else dispatches it against <html>, so the handler fires exactly once. removeAttribute is called immediately after to prevent re-fire, conceal the source from anti-tamper inspection, and avoid bloating the DOM by ~19 MB.
Cache invalidation embodiment
The cache key is the tuple { bundle identifier, rule-set content hash }. Redeployment by the vendor changes the bundle identifier (the hash segment of entry-<hash>.js); rule edits change patchesHash. Either axis independently forces exactly one rebuild, after which all reads are cache hits. This two-axis key is what allows the derivation subsystem to remain byte-stable (no timestamp in patches.json) while still invalidating on the two events that matter.
Runtime-wrapper embodiment
P-NP's patcher generates a prefix and suffix baked into manifest.json that build an entire modding runtime at load time, layered on top of the find/replace patches. The prefix/suffix together: (a) discover dependency-injection services by behavioral shape (enumerating the Inversify container's binding dictionary and matching services by duck-typed method/property presence) rather than by volatile minified identifiers; (b) install accessor-based facade properties and a setInterval that re-applies them every 500 ms to survive the game's repeated reassignment of shared globals; (c) override entitlement services in memory to force a bypassed membership tier; and (d) lazily load an external UI bundle by eval of fetched text whose URL is supplied through manifest.defaultMenuUrl. Idempotency guards within the prefix defend against the double-execution hazard that arises in the file-pull model when both the extension and the patcher suffix call SW.Load.decrementLoadSemaphore().
Claims
- 1.A method for altering, on an end-user device, the runtime behavior of a third-party single-page web application, comprising: blocking, via a browser extension's declarative network rules, the network request for the application's original script bundle; intercepting, in the page's JavaScript realm, every document-object-model insertion path for said bundle and neutralizing integrity attributes thereon; obtaining a transformed JavaScript bundle; and injecting the transformed bundle into the page's JavaScript realm by assigning it to an HTML event-handler content attribute of a document element and dispatching a corresponding synthetic event to execute it.
- 2.The method of claim 1, wherein injecting further comprises prepending to the transformed bundle one or more variable bindings that restore global identifiers shadowed by the event-handler's scope chain, including a binding of `URL` to the global `URL` constructor.
- 3.The method of claim 1, wherein injecting further comprises removing the event-handler content attribute after dispatch.
- 4.The method of claim 1, wherein obtaining comprises downloading, from a content-distribution endpoint, a bundle previously transformed by a scheduled server-side process (file-pull).
- 5.The method of claim 1, wherein obtaining comprises: downloading from a content-distribution endpoint a manifest of ordered regular-expression transformation rules and a content hash thereof; downloading the original bundle from the third-party application; and applying the rules to the original bundle within a background service worker of the extension to produce the transformed bundle (rules model).
- 6.The method of claim 5, further comprising caching the transformed bundle in extension-local storage under a key comprising a bundle identifier and the rule-set content hash, and serving a cached transformed bundle when both components of the key match.
- 7.The method of claim 5, wherein the extension's service-worker fetch of the original bundle is not subject to the extension's own declarative blocking rule.
- 8.The method of claim 1, wherein the transformed bundle is produced by a scheduled process that fetches the application markup using a browser-realistic User-Agent to bypass bot detection, extracts a versioned bundle URL, applies the ordered rules, and refuses to publish (or flags as degraded) when any rule's match count is below a per-rule minimum.
- 9.The method of claim 8, wherein the published rule manifest omits per-run timestamps so as to be byte-stable across runs that do not change the rules, and a separate timestamped telemetry artifact records per-run metadata.
- 10.The method of claim 1, wherein the page-realm injection is coordinated with a privileged extension context via custom DOM events or shared data attributes, the page realm lacking direct access to extension APIs.
- 11.The method of claim 5, further comprising injecting a generated wrapper that discovers application services by behavioral shape within a dependency-injection container rather than by identifier, and that periodically re-installs facade properties onto a shared global reassigned by the application.
- 12.A system comprising a scheduled derivation subsystem and an MV3 application subsystem configured to perform the method of any preceding claim, wherein redeployment of the third-party application is automatically accommodated within a bounded interval by re-derivation and republication, restoring altered behavior without modification of the installed extension in the rules-model embodiment.
Limitations and honest caveats
Appendix: artifact schemas and glossary
Artifact schemas
{
"schemaVersion": 1,
"patcherVersion": "2.2.1",
"hash": "2f38503a6bcc2b3f",
"rules": [
{ "id": "is-subscribed", "description": "…",
"find": "\\br\\(_?d\\[\\d+\\]\\)\\.isSubscribedStore\\.get\\(\\)",
"flags": "g", "replace": "(!0)", "minMatches": 1 },
{ "id": "subscription-status", "description": "…",
"find": "'subscribed'===\\(0,[\\w$]+\\.default\\)\\(this,[\\w$]+\\)\\[[\\w$]+\\]\\.state\\.snapshot\\?\\.subscription\\?\\.status",
"flags": "g", "replace": "(!0)", "minMatches": 1 }
]
}patches.json is the Gizmo Model B primary artifact (756 bytes). It deliberately omits any generatedAt field so it is byte-stable across no-op runs; the client uses hash as the cache-invalidation key.
{ "generatedAt": "2026-06-16T00:41:36.777Z", "patcherVersion": "2.2.1",
"source": { "entryUrl": "…/entry-227a4b389b2631e21b84b15ade4bdbb5.js" },
"perRuleCounts": { "is-subscribed": 3, "subscription-status": 16 },
"patchesHash": "2f38503a6bcc2b3f",
"bytes": { "in": 19286454, "out": 19285221 } }metadata.json carries the timestamped telemetry that patches.json deliberately omits. The CI commit step stages patches.json first; metadata.json is added only if the real artifacts changed.
{ "schemaVersion": 1, "patcherVersion": "4.4.1", "hash": "20c9e9be02bab3d9",
"rules": [ /* 6 rules with $n back-references */ ],
"prefix": "/* generated runtime prefix */",
"suffix": "/* generated runtime suffix + mod-menu loader */",
"defaultMenuUrl": "https://raw.githubusercontent.com/ProdigyPXP/ProdigyOrigin/master/originGUI/dist/bundle.js" }P-NP's manifest.json is the Model B primary artifact (~20 KB). It extends the schema with prefix, suffix, and defaultMenuUrl: the runtime wrapper baked in at derivation time.
type CacheEntry = {
bundleFilename: string;
patchesHash: string;
patchedBundle: string;
storedAt: number;
};CacheEntry is the shape stored in chrome.storage.local by the Gizmo Model B background worker. The {bundleFilename, patchesHash} tuple is the two-axis cache key; either changing forces a rebuild.
Glossary
MV3 / Manifest V3
: The current Chrome extension platform; restricts remote code execution and replaces webRequest blocking with declarativeNetRequest.
DNR (declarativeNetRequest) : Declarative request blocking, modification, and redirection by URL pattern. Supports leading scheme wildcards and bare path wildcards.
MAIN world / ISOLATED world
: The page's own JS realm vs. the extension's sandboxed content-script realm. They share the DOM but not JS scope; only ISOLATED has chrome.* access.
SRI (Subresource Integrity)
: integrity="sha…" on a <script> or <link> causing the browser to reject bytes that do not match the declared hash.
CSP
: Content-Security-Policy; restricts inline scripts, eval, and remote script execution by the page.
Entry / game bundle
: The minified application bundle: entry-<hash>.js for Gizmo, game.min.js for Prodigy.
onreset trick
: Injecting page-realm code via an HTML event-handler content attribute and a synthetic event, avoiding <script> insertion and extension-side eval.
(!0)
: A context-neutral truthy primary expression used as the universal replacement token. Evaluates to true and remains grammatically valid in every surrounding context a minifier produces.
minMatches
: Per-rule floor on match count. Converts silent regex rot into an explicit failure or patchDegraded flag, preventing a zero-match rule from silently publishing a broken artifact.
patchesHash / manifestHash
: sha256(canonical(rules[, wrapper])).slice(0,16); the content-stability and cache-invalidation key.
Self-healing : Automatic recovery of function after a third-party redeploy via scheduled re-derivation, without an extension update in the rules-model embodiment.