Commit 5643755589c for nodejs

commit 5643755589c2d2770cb650c12d6f9e48c00f60b8
Author: Filip Skokan <panva.ip@gmail.com>
Date:   Sun Sep 27 19:02:12 2026 +0200

    worker: convert importScripts arguments first

    Web IDL converts every argument before entering the method algorithm.
    Perform all USVString conversions before rejecting module workers or
    parsing URLs, so later conversions can throw or revoke blob URLs first.

    Signed-off-by: Filip Skokan <panva.ip@gmail.com>
    Assisted-by: Codex
    PR-URL: https://github.com/nodejs/node/pull/66354
    Reviewed-By: Anna Henningsen <anna@addaleax.net>
    Reviewed-By: James M Snell <jasnell@gmail.com>
    Reviewed-By: Aviv Keller <me@aviv.sh>

diff --git a/lib/internal/webworker.js b/lib/internal/webworker.js
index 228fb194d29..e798c814f28 100644
--- a/lib/internal/webworker.js
+++ b/lib/internal/webworker.js
@@ -507,6 +507,11 @@ class WorkerGlobalScope extends EventTarget {
   importScripts(...urls) {
     validateThisInternalField(this, kLocation, 'WorkerGlobalScope');
     const prefix = "Failed to execute 'importScripts' on 'WorkerGlobalScope'";
+    // Web IDL converts every argument before running the method steps.
+    for (let i = 0; i < urls.length; i++) {
+      urls[i] = converters.USVString(
+        urls[i], { prefix, context: `Argument ${i + 1}` });
+    }
     // "To import scripts into worker global scope, given a
     // WorkerGlobalScope object worker global scope, a list of scalar value
     // strings urls, and an optional perform the fetch hook performFetch:"
@@ -525,8 +530,7 @@ class WorkerGlobalScope extends EventTarget {
     const urlRecords = [];
     // "For each url of urls:"
     for (let i = 0; i < urls.length; i++) {
-      const url = converters.USVString(
-        urls[i], { prefix, context: `Argument ${i + 1}` });
+      const url = urls[i];
       // "Let urlRecord be the result of encoding-parsing a URL given url,
       // relative to settings object."
       const urlRecord = URLParse(url, this[kLocation].href);
diff --git a/test/parallel/test-webworker-importscripts-conversion.js b/test/parallel/test-webworker-importscripts-conversion.js
new file mode 100644
index 00000000000..5ea25281428
--- /dev/null
+++ b/test/parallel/test-webworker-importscripts-conversion.js
@@ -0,0 +1,67 @@
+// Flags: --experimental-web-worker
+'use strict';
+
+const common = require('../common');
+const assert = require('node:assert');
+
+for (const type of ['classic', 'module']) {
+  const source = `
+    const results = [];
+    const conversions = [];
+    const sentinel = new Error('conversion');
+    try {
+      importScripts('https://[', {
+        toString() { conversions.push('converted'); throw sentinel; }
+      });
+    } catch (error) {
+      results.push([conversions, error === sentinel]);
+    }
+    const order = [];
+    try {
+      importScripts(
+        { toString() { order.push(1); return 'https://['; } },
+        { toString() { order.push(2); return 'data:text/javascript,'; } }
+      );
+    } catch (error) {
+      results.push([order, error.name]);
+    }
+    postMessage(results);
+  `;
+  const worker = new Worker(`data:text/javascript,${encodeURIComponent(source)}`, { type });
+  worker.onerror = common.mustNotCall('worker failed');
+  worker.onmessage = common.mustCall(({ data }) => {
+    worker.terminate();
+    assert.deepStrictEqual(data, [
+      [['converted'], true],
+      [[1, 2], type === 'module' ? 'TypeError' : 'SyntaxError'],
+    ]);
+  });
+}
+
+if (common.hasCrypto) {
+  // URL parsing must capture blob entries after all arguments are converted.
+  const source = `
+    self.ran = false;
+    const url = URL.createObjectURL(new Blob(['self.ran = true'], {
+      type: 'text/javascript'
+    }));
+    let errorName;
+    try {
+      importScripts(url, {
+        toString() {
+          URL.revokeObjectURL(url);
+          return 'data:text/javascript,';
+        }
+      });
+    } catch (error) {
+      errorName = error.name;
+    }
+    postMessage([self.ran, errorName]);
+  `;
+  const worker = new Worker(`data:text/javascript,${encodeURIComponent(source)}`);
+  worker.onerror = common.mustNotCall('worker failed');
+  worker.onmessage = common.mustCall(({ data }) => {
+    worker.terminate();
+    assert.deepStrictEqual(data, [false, 'NetworkError']);
+  });
+}