← All issues

Web Extension Error Reporting with URL Masking Bypass

dde2f84

Source/WebCore/bindings/js/WebCoreJSClientData.cpp

+String unmaskedSourceURLFromException(const JSC::Exception& exception, JSC::VM& vm)
+{
+ for (auto& frame : exception.stack()) {
+ String url = frame.sourceURL(vm, JSC::AllowURLOverride::No);
+ if (!url.isEmpty() && url != "[native code]"_s)
+ return url;
+ }
+ return emptyString();
+}

Source/WebCore/bindings/js/JSDOMExceptionHandling.cpp

+ if (globalObject->hasScriptErrorCallbacks()) {
+ auto unmaskedSourceURL = exceptionSourceURL;
+ if (auto url = unmaskedSourceURLFromException(*exception, vm); !url.isEmpty())
+ unmaskedSourceURL = url;
+ globalObject->invokeScriptErrorCallbacks(errorMessage, unmaskedSourceURL, lineNumber, columnNumber);
+ }

This commit adds uncaught exception and unhandled promise rejection reporting for Web Extensions, routing errors to the extension context via a new WebProcess→UIProcess IPC message. It introduces an AllowURLOverride knob in JSC's StackFrame::sourceURL() to bypass webkit-masked-url://hidden/ masking when capturing real extension script URLs for internal error reporting. Content scripts injected into the main world normally use webkit-masked-url://hidden/ as their visible source URL — preventing host pages from fingerprinting installed extensions — but the error reporter needs the real URL for diagnostic purposes.

Content Script (main world)
  source URL visible to page:  webkit-masked-url://hidden/
  real URL (internal):         extension-url://abc/cs.js
         │
         └─ throws exception
                  │
                  ▼
         reportException()
           ├─ exceptionSourceURL (masked) ──► page onerror / console
           └─ hasScriptErrorCallbacks()?
                └─ Yes:
                     unmaskedSourceURLFromException()
                       │  StackFrame::sourceURL(AllowURLOverride::No)
                       ▼
                     real URL extracted → IPC → UIProcess

The AllowURLOverride::No path creates a deliberate bypass of the URL masking mechanism — if accessible outside the intended extension error reporting context, it would defeat the content script fingerprinting protection.

hasScriptErrorCallbacks() gates the unmasked URL extraction. If a non-extension global object (regular page window, worker) could have script error callbacks registered — perhaps via a type confusion or unexpected call path — the unmasked real URL of an extension content script could be delivered to the wrong party. The new IPC message didEncounterScriptError carries source URLs across the WebProcess→UIProcess boundary — the UIProcess side should validate that reported URLs actually belong to the extension.