diff --git a/lib/internal/modules/esm/get_format.js b/lib/internal/modules/esm/get_format.js index 4f334c7d88c336..78f338226cc137 100644 --- a/lib/internal/modules/esm/get_format.js +++ b/lib/internal/modules/esm/get_format.js @@ -97,7 +97,7 @@ function detectModuleFormat(source, url) { */ function getDataProtocolModuleFormat(parsed) { const { 1: mime } = RegExpPrototypeExec( - /^([^/]+\/[^;,]+)(?:[^,]*?)(;base64)?,/, + /^([^/]+\/[^;,]+)(?:;[^,]*)?,/, parsed.pathname, ) || [ null, null, null ]; diff --git a/lib/internal/modules/esm/load.js b/lib/internal/modules/esm/load.js index c284163fba86ec..70c3fc89222bbf 100644 --- a/lib/internal/modules/esm/load.js +++ b/lib/internal/modules/esm/load.js @@ -205,7 +205,7 @@ function throwIfUnsupportedURLScheme(parsed) { */ function throwUnknownModuleFormat(url, format) { const dataUrl = RegExpPrototypeExec( - /^data:([^/]+\/[^;,]+)(?:[^,]*?)(;base64)?,/, + /^data:([^/]+\/[^;,]+)(?:;[^,]*)?,/, url, ); diff --git a/test/parallel/test-esm-data-url-format-regex-backtracking.js b/test/parallel/test-esm-data-url-format-regex-backtracking.js new file mode 100644 index 00000000000000..29b7cbae3ab7cb --- /dev/null +++ b/test/parallel/test-esm-data-url-format-regex-backtracking.js @@ -0,0 +1,19 @@ +// Flags: --expose-internals +'use strict'; + +const common = require('../common'); +const assert = require('assert'); +const { defaultGetFormat } = require('internal/modules/esm/get_format'); + +// Regression test for #61904. This malformed data URL path is crafted to +// stress the MIME regex without triggering URL parsing failures. +const longPath = `data:a/${'a'.repeat(2 ** 17)}B`; +const start = process.hrtime.bigint(); +const format = defaultGetFormat(new URL(longPath), { parentURL: undefined }); +const elapsedMs = Number(process.hrtime.bigint() - start) / 1e6; + +assert.strictEqual(format, null); +assert.ok( + elapsedMs < common.platformTimeout(1000), + `Expected format detection to complete quickly, took ${elapsedMs}ms`, +);