From f0a6b7be593049339d13eaaed07036bc9e26defa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcos=20C=C3=A1ceres?= Date: Tue, 14 Apr 2026 08:19:35 +1000 Subject: [PATCH 1/7] Potential fix for code scanning alert no. 24: Client-side URL redirect Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- worker/respec-worker.js | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/worker/respec-worker.js b/worker/respec-worker.js index 238518f5fc..989a97f41d 100644 --- a/worker/respec-worker.js +++ b/worker/respec-worker.js @@ -15,8 +15,28 @@ self.addEventListener("message", ({ data: originalData }) => { switch (data.action) { case "highlight-load-lang": { const { langURL, propName, lang } = data; - importScripts(langURL); - self.hljs.registerLanguage(lang, self[propName]); + try { + const parsedURL = new URL(langURL, self.location.href); + const isAllowedProtocol = + parsedURL.protocol === "https:" || parsedURL.protocol === "http:"; + const isSameOrigin = parsedURL.origin === self.location.origin; + const isJavaScriptFile = parsedURL.pathname.endsWith(".js"); + const isValidPropName = /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(propName); + + if (!isAllowedProtocol || !isSameOrigin || !isJavaScriptFile || !isValidPropName) { + throw new Error("Invalid language module request"); + } + + importScripts(parsedURL.href); + + if (typeof self[propName] !== "function") { + throw new Error("Loaded language module did not expose a valid language definition"); + } + + self.hljs.registerLanguage(lang, self[propName]); + } catch (err) { + console.error("Invalid language load request", err); + } break; } case "highlight": { From da4150cd143957ec49329b8be33d9ec876e77f46 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 14 Apr 2026 03:04:23 +0000 Subject: [PATCH 2/7] fix(worker): validate URL origin before importScripts in highlight-load-lang Co-authored-by: marcoscaceres <870154+marcoscaceres@users.noreply.github.com> --- worker/respec-worker.js | 1 + 1 file changed, 1 insertion(+) diff --git a/worker/respec-worker.js b/worker/respec-worker.js index 989a97f41d..3e764aa38e 100644 --- a/worker/respec-worker.js +++ b/worker/respec-worker.js @@ -1,3 +1,4 @@ +// @ts-check // ReSpec Worker v1.0.0 "use strict"; // hljs is either inlined by core/worker.js (preferred) or loaded below via From a3c48159e62f35419de758a472ec8237f872eb32 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 14 Apr 2026 14:22:55 +0000 Subject: [PATCH 3/7] fix(worker): fix prettier formatting in respec-worker.js Agent-Logs-Url: https://github.com/speced/respec/sessions/eaf97df3-cfd4-4999-92cf-047f0b3b3ca4 Co-authored-by: marcoscaceres <870154+marcoscaceres@users.noreply.github.com> --- worker/respec-worker.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/worker/respec-worker.js b/worker/respec-worker.js index 3e764aa38e..6de994dc80 100644 --- a/worker/respec-worker.js +++ b/worker/respec-worker.js @@ -24,14 +24,21 @@ self.addEventListener("message", ({ data: originalData }) => { const isJavaScriptFile = parsedURL.pathname.endsWith(".js"); const isValidPropName = /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(propName); - if (!isAllowedProtocol || !isSameOrigin || !isJavaScriptFile || !isValidPropName) { + if ( + !isAllowedProtocol || + !isSameOrigin || + !isJavaScriptFile || + !isValidPropName + ) { throw new Error("Invalid language module request"); } importScripts(parsedURL.href); if (typeof self[propName] !== "function") { - throw new Error("Loaded language module did not expose a valid language definition"); + throw new Error( + "Loaded language module did not expose a valid language definition" + ); } self.hljs.registerLanguage(lang, self[propName]); From c9a2e1c1ccc08281d26e190432ca57c2dcbf6616 Mon Sep 17 00:00:00 2001 From: Marcos Caceres Date: Fri, 17 Apr 2026 17:56:00 +1000 Subject: [PATCH 4/7] fix(worker): remove dead highlight-load-lang code path The highlight-load-lang action is unused by production code (see #4934). The same-origin check added by Copilot Autofix was broken in blob workers (self.location.origin is "null"), silently breaking the only remaining consumer. Remove the dead code instead of hardening it. --- worker/respec-worker.js | 58 +++++++---------------------------------- 1 file changed, 10 insertions(+), 48 deletions(-) diff --git a/worker/respec-worker.js b/worker/respec-worker.js index 6de994dc80..642ca2cdba 100644 --- a/worker/respec-worker.js +++ b/worker/respec-worker.js @@ -1,5 +1,4 @@ -// @ts-check -// ReSpec Worker v1.0.0 +// ReSpec Worker v1.1.0 "use strict"; // hljs is either inlined by core/worker.js (preferred) or loaded below via // importScripts as a fallback when the inline fetch was not possible. @@ -13,52 +12,15 @@ if (typeof self.hljs === "undefined" && self.RESPEC_HIGHLIGHT_URL) { self.addEventListener("message", ({ data: originalData }) => { const data = Object.assign({}, originalData); - switch (data.action) { - case "highlight-load-lang": { - const { langURL, propName, lang } = data; - try { - const parsedURL = new URL(langURL, self.location.href); - const isAllowedProtocol = - parsedURL.protocol === "https:" || parsedURL.protocol === "http:"; - const isSameOrigin = parsedURL.origin === self.location.origin; - const isJavaScriptFile = parsedURL.pathname.endsWith(".js"); - const isValidPropName = /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(propName); - - if ( - !isAllowedProtocol || - !isSameOrigin || - !isJavaScriptFile || - !isValidPropName - ) { - throw new Error("Invalid language module request"); - } - - importScripts(parsedURL.href); - - if (typeof self[propName] !== "function") { - throw new Error( - "Loaded language module did not expose a valid language definition" - ); - } - - self.hljs.registerLanguage(lang, self[propName]); - } catch (err) { - console.error("Invalid language load request", err); - } - break; - } - case "highlight": { - const { code } = data; - const langs = data.languages.length ? data.languages : undefined; - try { - const { value, language } = self.hljs.highlightAuto(code, langs); - Object.assign(data, { value, language }); - } catch (err) { - console.error("Could not transform some code?", err); - // Post back the original code - Object.assign(data, { value: code, language: "" }); - } - break; + if (data.action === "highlight") { + const { code } = data; + const langs = data.languages.length ? data.languages : undefined; + try { + const { value, language } = self.hljs.highlightAuto(code, langs); + Object.assign(data, { value, language }); + } catch (err) { + console.error("Could not transform some code?", err); + Object.assign(data, { value: code, language: "" }); } } self.postMessage(data); From 54686e5d4f43b7884702845f767eb0d0242b4216 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 17 Apr 2026 17:27:54 +0000 Subject: [PATCH 5/7] fix(tests): remove dead highlight-load-lang test and fixtures Agent-Logs-Url: https://github.com/speced/respec/sessions/78a14774-8331-43c0-b95e-83e38a6bd570 Co-authored-by: marcoscaceres <870154+marcoscaceres@users.noreply.github.com> --- tests/spec/core/highlight-spec.js | 6 --- tests/spec/core/highlight.html | 55 ---------------------------- tests/support-files/hljs-testlang.js | 14 ------- 3 files changed, 75 deletions(-) delete mode 100644 tests/spec/core/highlight.html delete mode 100644 tests/support-files/hljs-testlang.js diff --git a/tests/spec/core/highlight-spec.js b/tests/spec/core/highlight-spec.js index 529168f442..e68a74e2e6 100644 --- a/tests/spec/core/highlight-spec.js +++ b/tests/spec/core/highlight-spec.js @@ -11,12 +11,6 @@ import { describe("Core — Highlight", () => { afterAll(flushIframes); - it("highlights remote languages not bundled by default with ReSpec", async () => { - const doc = await makeRSDoc({}, "spec/core/highlight.html"); - const span = doc.querySelector("code.testlang span[class*=hljs]"); - expect(span.textContent).toBe("funkyFunction"); - }); - it("shouldn't highlight idl blocks", async () => { const body = `
diff --git a/tests/spec/core/highlight.html b/tests/spec/core/highlight.html
deleted file mode 100644
index e864c15062..0000000000
--- a/tests/spec/core/highlight.html
+++ /dev/null
@@ -1,55 +0,0 @@
-
-
-  
-    
-    Replace me with a real title
-    
-    
-  
-  
-    
-

- This is required. -

-
-
-

- This is required. -

-
-        funkyFunction
-      
-
- - diff --git a/tests/support-files/hljs-testlang.js b/tests/support-files/hljs-testlang.js deleted file mode 100644 index 60de24e5ed..0000000000 --- a/tests/support-files/hljs-testlang.js +++ /dev/null @@ -1,14 +0,0 @@ -var module = module ? module : {}; // eslint-disable-line - -function testLang() { - return { - aliases: ["test"], - keywords: ["funkyFunction"], - }; -} - -module.exports = function (hljs) { - hljs.registerLanguage("funkytest", testLang); -}; - -module.exports.definer = testLang; From b094c5c174314a14da1c29220eccd2ebc0c0be51 Mon Sep 17 00:00:00 2001 From: Marcos Caceres Date: Sat, 18 Apr 2026 05:22:50 +1000 Subject: [PATCH 6/7] chore(worker): drop manual version comment (not consumed anywhere) --- worker/respec-worker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worker/respec-worker.js b/worker/respec-worker.js index 642ca2cdba..a793307190 100644 --- a/worker/respec-worker.js +++ b/worker/respec-worker.js @@ -1,4 +1,4 @@ -// ReSpec Worker v1.1.0 +// ReSpec Worker "use strict"; // hljs is either inlined by core/worker.js (preferred) or loaded below via // importScripts as a fallback when the inline fetch was not possible. From 09e1b1d0320a8698bfc3e588591ffe4b4d85072d Mon Sep 17 00:00:00 2001 From: Marcos Caceres Date: Sat, 18 Apr 2026 12:43:44 +1000 Subject: [PATCH 7/7] fix(worker): drop unnecessary clone, guard postMessage, add defensive optional chain - Remove Object.assign clone (structured clone already provides fresh data) - Early return for non-highlight actions (don't echo unknown messages) - Add optional chain on data.languages for robustness --- worker/respec-worker.js | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/worker/respec-worker.js b/worker/respec-worker.js index a793307190..d10cbb99d8 100644 --- a/worker/respec-worker.js +++ b/worker/respec-worker.js @@ -10,18 +10,16 @@ if (typeof self.hljs === "undefined" && self.RESPEC_HIGHLIGHT_URL) { } } -self.addEventListener("message", ({ data: originalData }) => { - const data = Object.assign({}, originalData); - if (data.action === "highlight") { - const { code } = data; - const langs = data.languages.length ? data.languages : undefined; - try { - const { value, language } = self.hljs.highlightAuto(code, langs); - Object.assign(data, { value, language }); - } catch (err) { - console.error("Could not transform some code?", err); - Object.assign(data, { value: code, language: "" }); - } +self.addEventListener("message", ({ data }) => { + if (data.action !== "highlight") return; + const { code } = data; + const langs = data.languages?.length ? data.languages : undefined; + try { + const { value, language } = self.hljs.highlightAuto(code, langs); + Object.assign(data, { value, language }); + } catch (err) { + console.error("Could not transform some code?", err); + Object.assign(data, { value: code, language: "" }); } self.postMessage(data); });