Skip to content

document.currentScript is not implemented — dynamically injected scripts that read it crash (breaks Google sign-in on x.com) #77

Description

@codymullins

document.currentScript does not exist in Starling. Google's https://accounts.google.com/gsi/client ends with a style-injection IIFE that reads document.currentScript.nonce. The read throws TypeError: Cannot read properties of undefined (reading 'nonce'), the Starling DOM fires the script element's error event instead of load, and x.com treats Google Identity Services as failed — Google sign-in never initializes. Logged as uncaught dynamic script error (https://accounts.google.com/gsi/client).

What happens

  • A repo-wide grep for currentScript in src/ has zero hits. The document prototype accessor block (src/Starling.Bindings/NodeBindings.cs, starting around line 1487 — readyState, body, head, activeElement, and so on) defines no currentScript.
  • The dynamic classic-script path StarlingDynamicScriptRunner.RunOneAsync (src/Starling.Bindings/Backend/StarlingDynamicScriptRunner.cs:93-157, the run at line 139) holds the script element in scope but never sets a current-script slot around the run.
  • The parser-batch path cannot do it today even if it wanted to: IScriptSession.RunClassicScript(string source, string label) (src/Starling.Js.Hosting/IScriptSession.cs:95, implemented at src/Starling.Bindings/Backend/StarlingScriptSession.cs:126-178, called from src/Starling.Engine/Engine.cs:1477) does not receive the script element. A seam change is needed.
  • Reading the missing property yields undefined, and the .nonce member read throws via src/Starling.Js/Runtime/JsVm.cs:1133. The dynamic runner contains the failure (StarlingDynamicScriptRunner.cs:143-148, log template at line 191) and fires error instead of load on the element.
  • Also missing: the nonce IDL (interface definition language) attribute on elements. Chromium exposes it on HTMLElement.prototype and returns "" by default.

Chromium ground truth (verified 2026-06-10 via Playwright): during a dynamically inserted classic script's execution, document.currentScript is the script element, element.nonce is "", and currentScript reverts to null afterwards. Module scripts always see null.

Repro

Verified 2026-06-10 on the real engine via a scratch harness (console app referencing Starling.Bindings, driving CreateSession + RunClassicScript + a pump). A page script injects <script src=...>. The probe script observes typeof document.currentScript === "undefined", then document.currentScript.nonce throws the exact observed TypeError, and error fires instead of load. The parser-batch path also reports undefined.

Fix

Real fix: implement the HTML "execute the script block" current-script steps:

  • a per-document slot (not per-realm — iframes share the realm bootstrap, but each document needs its own slot)
  • set to the element before running a classic script, restored after (and null for module scripts)
  • applied on both paths: the dynamic runner (the element is already in scope) and the parser batch (pass the element through the RunClassicScript seam, or have the engine set the Starling DOM slot before the call)
  • add the HTMLElement.nonce IDL attribute (default "", reflects the content attribute) for parity — other loaders that are aware of Content Security Policy read it the same way

There is no cheap stub. Defining document.currentScript as a constant null does not fix gsi/client: null.nonce throws the same TypeError, just with a different message. Only the real slot, set during execution, makes the guard evaluate to the falsy "" and lets the script finish.

Context

Found during the x.com/nasa boot investigation on 2026-06-10 (branch feat/js-stack-trampoline). The crash is the file's last statement, so the GSI library body has already executed when it dies — but the error event makes loaders treat the whole script as failed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    browserRelates to the browser subsystembugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions