npm / playwright / 1.65.0-alpha-2026-10-23

playwright 1.65.0-alpha-2026-10-23

Source
https://github.com/microsoft/playwright
Artifact scanned
playwright-1.65.0-alpha-2026-10-23.tgz (npm tarball · 887.5 KB · SHA-256 39ef36d9e0b8…)
Compared with
playwright-1.65.0-alpha-2026-10-22.tgz (1 signals introduced since)
Files
55 scanned, 5 skipped (binary, oversized, or unrecognised)
Signals
0 critical · 0 warn · 60 info
Scan time
28.2 s
LLM review
Reviewed by claude-haiku-5-5 (Anthropic): 32 of 32 warn and critical signals; 32 demoted to info.
Disclude version
4.3.0
Scanned (UTC)
2026-10-23 09:29

Signals

Ordered by severity, then signals introduced in this release. Hidden characters are shown as ⟨U+…⟩.

  1. info long-line README.md:3:1 new in this release

    line length 741 characters (raw pass, confidence 0.50)

    [![npm version]https://img.shields.io/npm/v/playwright.svg]https://www.npmjs.com/package/playwright <!-- GEN:chromium-version-badge -->[![Chromium version]https://img.shields.io/badge/chromium-157.0.8103.6-blue.svg?logo=google-chrome]https://www.chromium.org/Home<!-- GEN:stop --> <!-- GEN:firefox-version-badge 
  2. info warn → info by review dynamic-import lib/common/index.js:1124:30

    `require` called with a non-literal specifier (ast pass, confidence 0.60)

      process.env.BROWSERSLIST_IGNORE_OLD_DATA = "true";
      const { babelTransform } = require((0, import_package3.libPath)("transform", "babelBundle"));
      const babelResult = babelTransform(originalCode, filename, !!moduleUrl, pluginsEpilogue, useDefineForClassFields, jsx);
      if (!babelResult?.code)
    likely benign LLM, confidence 0.85 Loads the package's own bundled babel transform module via a computed path.
    Reasoning

    The require specifier is built from the package's own libPath helper to load the bundled babel transform. This is a self-referential internal load, not attacker-controlled input.

  3. info critical → info by review dynamic-execution lib/common/index.js:1141:29

    `eval` called with a non-literal expression (ast pass, confidence 0.90)

        const fileName = import_url2.default.pathToFileURL(file);
        const esmImport = () => eval(`import(${JSON.stringify(fileName)})`);
        if (loaderChannel) {
    likely benign LLM, confidence 0.85 Uses eval to hide a dynamic ESM import of a test file from transpilation.
    Reasoning

    The eval wraps a dynamic import() so that the bundler or transpiler does not rewrite it into require. The argument is a file URL produced by pathToFileURL and JSON-stringified, so the code is not attacker-controlled. This is a known test-loader idiom.

  4. info critical → info by review dynamic-execution lib/common/index.js:1143:13

    `eval` called with a non-literal expression (ast pass, confidence 0.90)

        if (loaderChannel) {
          await eval(`import(${JSON.stringify(fileName + ".esm.preflight")})`).catch((error) => debugTest("Failed to load preflight for " + file + ", source maps may be missing for errors thrown during loading.", error)).finally(nextTask);
        }
        return await esmImport().finally(nextTask);
    likely benign LLM, confidence 0.85 Eval-wrapped dynamic import of an optional preflight module next to a test file.
    Reasoning

    Same idiom as the sibling finding: eval of import() with a JSON-stringified, derived file path to load an optional preflight ESM module. Not an obfuscated payload.

  5. info warn → info by review dynamic-import lib/common/index.js:1147:18

    `require` called with a non-literal specifier (ast pass, confidence 0.60)

      }
      const result = require(file);
      const depsCollector = currentFileDepsCollector();
      if (depsCollector) {
    likely benign LLM, confidence 0.80 Requires the test file being loaded by the runner.
    Reasoning

    The require loads the user's own test file path during test loading. Dynamic loading of user-specified test modules is the expected behavior of a test runner.

  6. line length 572 characters (raw pass, confidence 0.50)

          return "string" === typeof type || "function" === typeof type || type === REACT_FRAGMENT_TYPE || type === REACT_PROFILER_TYPE || type === REACT_STRICT_MODE_TYPE || type === REACT_SUSPENSE_TYPE || type === REACT_SUSPENSE_LIST_TYPE || "object" === typeof type && null !== type && (type.$$typeof === REACT_LAZY_TYPE |
  7. line length 997 characters (raw pass, confidence 0.50)

          var REACT_ELEMENT_TYPE = /* @__PURE__ */ Symbol.for("react.transitional.element"), REACT_PORTAL_TYPE = /* @__PURE__ */ Symbol.for("react.portal"), REACT_FRAGMENT_TYPE = /* @__PURE__ */ Symbol.for("react.fragment"), REACT_STRICT_MODE_TYPE = /* @__PURE__ */ Symbol.for("react.strict_mode"), REACT_PROFILER_TYPE = /* 
  8. line length 574 characters (raw pass, confidence 0.50)

            return "string" === typeof type || "function" === typeof type || type === REACT_FRAGMENT_TYPE || type === REACT_PROFILER_TYPE || type === REACT_STRICT_MODE_TYPE || type === REACT_SUSPENSE_TYPE || type === REACT_SUSPENSE_LIST_TYPE || "object" === typeof type && null !== type && (type.$$typeof === REACT_LAZY_TYPE
  9. line length 638 characters (raw pass, confidence 0.50)

        exports2.default = /((['"])(?:(?!\2|\\).|\\(?:\r\n|[\s\S]))*(\2)?|`(?:[^`\\$]|\\[\s\S]|\$(?!\{)|\$\{(?:[^{}]|\{[^}]*\}?)*\}?)*(`)?)|(\/\/.*)|(\/\*(?:[^*]|\*(?!\/))*(\*\/)?)|(\/(?!\*)(?:\[(?:(?![\]\\]).|\\.)*\]|(?![\/\]\\]).|\\.)+\/(?:(?!\s*(?:\b|[\u0080-\uFFFF$\\'"~({]|[+\-!](?!=)|\.?\d))|[gmiyus]{1,6}\b(?![\u0080-
  10. info warn → info by review long-line lib/matchers/expect.js:5876:1

    line length 2269 characters (raw pass, confidence 0.65)

        var astralIdentifierStartCodes = [0, 11, 2, 25, 2, 18, 2, 1, 2, 14, 3, 13, 35, 122, 70, 52, 268, 28, 4, 48, 48, 31, 14, 29, 6, 37, 11, 29, 3, 35, 5, 7, 2, 4, 43, 157, 19, 35, 5, 35, 5, 39, 9, 51, 13, 10, 2, 14, 2, 6, 2, 1, 2, 10, 2, 14, 2, 6, 2, 1, 4, 51, 13, 310, 10, 21, 11, 7, 25, 5, 2, 41, 2, 8, 70, 5, 3, 0, 2, 
    likely benign LLM, confidence 0.90 A long numeric lookup table of Unicode identifier code points.
    Reasoning

    The very long line is a table of Unicode code point ranges for identifier-start and identifier-part characters, as found in the bundled babel or jest parser. Long data tables are common in generated code and this one carries no executable content.

  11. info warn → info by review dynamic-import lib/matchers/expect.js:10216:44

    dynamic `import(...)` with a non-literal specifier (ast pass, confidence 0.65)

                  const moduleUrl = (0, _nodeUrl().pathToFileURL)(filePath);
                  const importedModule = await import(
                    /* webpackIgnore: true */
                    moduleUrl.href
    likely benign LLM, confidence 0.85 Dynamic import of a user module by file URL inside the bundled expect module loader.
    Reasoning

    This is the standard jest-style ESM loader that imports a module by file URL, with a webpackIgnore hint. The path comes from the test configuration, not from untrusted input.

  12. info warn → info by review dynamic-import lib/matchers/expect.js:10242:38

    `require` called with a non-literal specifier (ast pass, confidence 0.60)

                  }
                  const requiredModule = require(filePath);
                  if (!applyInteropRequireDefault) {
                    return requiredModule;
    likely benign LLM, confidence 0.85 CJS require of a resolved module path in the bundled loader.
    Reasoning

    This is the CJS fallback of the same module loader, requiring a resolved file path. It is ordinary module loading with no decoding or network activity.

  13. line length 543 characters (raw pass, confidence 0.50)

        const message = pass ? () => matcherHint(matcherName, void 0, void 0, options) + "\n\n" + printExpectedConstructorNameNot("Expected constructor", expected) + (typeof received.constructor === "function" && received.constructor !== expected ? printReceivedConstructorNameNot("Received constructor", received.constructo
  14. line length 766 characters (raw pass, confidence 0.50)

      const message = pass ? () => matcherHint(matcherName, void 0, void 0, options) + "\n\n" + formatExpected("Expected asymmetric matcher: not ", expected) + "\n" + (thrown !== null && thrown.hasMessage ? formatReceived("Received name:    ", thrown, "name") + formatReceived("Received message: ", thrown, "message") + form
  15. line length 539 characters (raw pass, confidence 0.50)

      const message = pass ? () => matcherHint(matcherName, void 0, void 0, options) + "\n\n" + formatExpected(`Expected ${messageAndCause(expected)}: not `, expectedMessageAndCause) + (thrown !== null && thrown.hasMessage ? formatStack(thrown) : formatReceived("Received value:       ", thrown, "value")) : () => matcherHin
  16. line length 756 characters (raw pass, confidence 0.50)

      const message = pass ? () => matcherHint(matcherName, void 0, void 0, options) + "\n\n" + printExpectedConstructorNameNot("Expected constructor", expected) + (thrown !== null && thrown.value !== null && thrown.value !== void 0 && typeof thrown.value.constructor === "function" && thrown.value.constructor !== expected 
  17. info warn → info by review dynamic-import lib/package.js:38:21

    `require` called with a non-literal specifier (ast pass, confidence 0.60)

    const packageRoot = import_path.default.join(__dirname, "..");
    const packageJSON = require(import_path.default.join(packageRoot, "package.json"));
    function libPath(...parts) {
      return import_path.default.join(packageRoot, "lib", ...parts);
    likely benign LLM, confidence 0.90 Reads the package's own package.json at load time.
    Reasoning

    The require reads the package's own package.json via a path built from __dirname. This is a standard, benign pattern.

  18. info warn → info by review dynamic-execution lib/runner/index.js:272:80

    `atob` decodes a base64 value at runtime — common step before dynamic fetch or eval (ast pass, confidence 0.75)

      _onStdIO(type, testId, resultId, data, isBase64) {
        const chunk = isBase64 ? globalThis.Buffer ? Buffer.from(data, "base64") : atob(data) : data;
        const test = testId ? this._tests.get(testId) : void 0;
        const result = test && resultId ? test.results.find((r) => r._id === resultId) : void 0;
    likely benign LLM, confidence 0.85 Decodes base64-encoded worker stdout/stderr chunks for reporting.
    Reasoning

    atob decodes base64 stdio chunks forwarded from worker processes when isBase64 is set. The decoded data is written as output, not evaluated or fetched, so this is ordinary output plumbing.

  19. info warn → info by review dynamic-import lib/runner/index.js:3242:27

    `require` called with a non-literal specifier (ast pass, confidence 0.60)

          const resolveFrom = (name) => require.resolve(name, { paths: [this._options.configDir] });
          const libCoverage = require(resolveFrom("istanbul-lib-coverage"));
          const libReport = require(resolveFrom("istanbul-lib-report"));
          const reports = require(resolveFrom("istanbul-reports"));
    likely benign LLM, confidence 0.80 Loads istanbul-lib-coverage from the project's config directory for coverage reporting.
    Reasoning

    The coverage library is resolved relative to the config directory, which is the normal way a test runner loads optional reporting dependencies. Nothing is decoded or executed beyond a plain require.

  20. info warn → info by review dynamic-import lib/runner/index.js:3243:25

    `require` called with a non-literal specifier (ast pass, confidence 0.60)

          const libCoverage = require(resolveFrom("istanbul-lib-coverage"));
          const libReport = require(resolveFrom("istanbul-lib-report"));
          const reports = require(resolveFrom("istanbul-reports"));
          const context = libReport.createContext({
    likely benign LLM, confidence 0.80 Loads istanbul-lib-report for coverage output.
    Reasoning

    Loads istanbul-lib-report through the same config-relative resolution used for coverage reporting. Standard behavior.

  21. info warn → info by review dynamic-import lib/runner/index.js:3244:23

    `require` called with a non-literal specifier (ast pass, confidence 0.60)

          const libReport = require(resolveFrom("istanbul-lib-report"));
          const reports = require(resolveFrom("istanbul-reports"));
          const context = libReport.createContext({
            dir: outputDir,
    likely benign LLM, confidence 0.80 Loads istanbul-reports for coverage report generation.
    Reasoning

    Loads istanbul-reports for coverage reporters through the standard config-relative resolver. Standard behavior.

  22. info whitespace-anomaly lib/transform/babelBundle.js:9:1

    file mixes tab and space indentation (10 tab-indented and 71066 space-indented lines) (raw pass, confidence 0.40)

    var __commonJS = (cb, mod) => function __require() {
      try {
        return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
      } catch (e) {
  23. info warn → info by review long-line lib/transform/babelBundle.js:3079:1

    line length 2269 characters (raw pass, confidence 0.65)

        var astralIdentifierStartCodes = [0, 11, 2, 25, 2, 18, 2, 1, 2, 14, 3, 13, 35, 122, 70, 52, 268, 28, 4, 48, 48, 31, 14, 29, 6, 37, 11, 29, 3, 35, 5, 7, 2, 4, 43, 157, 19, 35, 5, 35, 5, 39, 9, 51, 13, 10, 2, 14, 2, 6, 2, 1, 2, 10, 2, 14, 2, 6, 2, 1, 4, 51, 13, 310, 10, 21, 11, 7, 25, 5, 2, 41, 2, 8, 70, 5, 3, 0, 2, 
    likely benign LLM, confidence 0.95 A long array literal of Unicode identifier code points inside a bundled Babel library.
    Reasoning

    The long line is a numeric code-point table for astral identifier start characters, a standard pattern in bundled Babel parser code. The raw long-line signal is a formatting artifact, not obfuscation.

  24. line length 584 characters (raw pass, confidence 0.50)

        exports2.UPDATE_OPERATORS = exports2.UNARY_OPERATORS = exports2.STRING_UNARY_OPERATORS = exports2.STATEMENT_OR_BLOCK_KEYS = exports2.NUMBER_UNARY_OPERATORS = exports2.NUMBER_BINARY_OPERATORS = exports2.LOGICAL_OPERATORS = exports2.INHERIT_KEYS = exports2.FOR_INIT_KEYS = exports2.FLATTENABLE_KEYS = exports2.EQUALITY
  25. info warn → info by review long-line lib/transform/babelBundle.js:10081:1

    line length 2864 characters (raw pass, confidence 0.65)

        exports2.JSXIdentifier = exports2.JSXFragment = exports2.JSXExpressionContainer = exports2.JSXEmptyExpression = exports2.JSXElement = exports2.JSXClosingFragment = exports2.JSXClosingElement = exports2.JSXAttribute = exports2.IntersectionTypeAnnotation = exports2.InterpreterDirective = exports2.InterfaceTypeAnnotat
    likely benign LLM, confidence 0.95 A long chain of exports assignments for AST node types in a bundled Babel library.
    Reasoning

    The long line is a generated list of exports assignments, typical of the transpiled Babel AST type module. Length alone indicates nothing malicious.

  26. info warn → info by review long-line lib/transform/babelBundle.js:10082:1

    line length 2895 characters (raw pass, confidence 0.65)

        exports2.TSNumberKeyword = exports2.TSNullKeyword = exports2.TSNonNullExpression = exports2.TSNeverKeyword = exports2.TSNamespaceExportDeclaration = exports2.TSNamedTupleMember = exports2.TSModuleDeclaration = exports2.TSModuleBlock = exports2.TSMethodSignature = exports2.TSMappedType = exports2.TSLiteralType = exp
    likely benign LLM, confidence 0.95 A long chain of exports assignments for TypeScript AST node types in a bundled library.
    Reasoning

    This is the same generated exports-assignment chain for TypeScript AST node types. It is standard bundler output with no decoding or execution.

  27. line length 1618 characters (raw pass, confidence 0.50)

        exports2.YieldExpression = exports2.WithStatement = exports2.WhileStatement = exports2.VoidTypeAnnotation = exports2.VoidPattern = exports2.Variance = exports2.VariableDeclarator = exports2.VariableDeclaration = exports2.V8IntrinsicIdentifier = exports2.UpdateExpression = exports2.UnionTypeAnnotation = exports2.Una
  28. line length 1460 characters (raw pass, confidence 0.50)

        exports2.WHILE_TYPES = exports2.USERWHITESPACABLE_TYPES = exports2.UNARYLIKE_TYPES = exports2.TYPESCRIPT_TYPES = exports2.TSTYPE_TYPES = exports2.TSTYPEELEMENT_TYPES = exports2.TSENTITYNAME_TYPES = exports2.TSBASETYPE_TYPES = exports2.TERMINATORLESS_TYPES = exports2.STATEMENT_TYPES = exports2.STANDARDIZED_TYPES = e
  29. info warn → info by review long-line lib/transform/babelBundle.js:15700:1

    line length 2269 characters (raw pass, confidence 0.65)

        var astralIdentifierStartCodes = [0, 11, 2, 25, 2, 18, 2, 1, 2, 14, 3, 13, 35, 122, 70, 52, 268, 28, 4, 48, 48, 31, 14, 29, 6, 37, 11, 29, 3, 35, 5, 7, 2, 4, 43, 157, 19, 35, 5, 35, 5, 39, 9, 51, 13, 10, 2, 14, 2, 6, 2, 1, 2, 10, 2, 14, 2, 6, 2, 1, 4, 51, 13, 310, 10, 21, 11, 7, 25, 5, 2, 41, 2, 8, 70, 5, 3, 0, 2, 
    likely benign LLM, confidence 0.95 A long array of astral Unicode identifier code points in a bundled Babel library.
    Reasoning

    This is a duplicate of the astral identifier table found elsewhere in the same bundle, a legitimate Unicode data array.

  30. line length 509 characters (raw pass, confidence 0.50)

        var reservedWordLikeSet = /* @__PURE__ */ new Set(["break", "case", "catch", "continue", "debugger", "default", "do", "else", "finally", "for", "function", "if", "return", "switch", "throw", "try", "var", "const", "while", "with", "new", "this", "super", "class", "extends", "export", "import", "null", "true", "fals
  31. line length 825 characters (raw pass, confidence 0.50)

            var _node$directive, _node$decorators, _node$optional, _node$typeAnnotation, _node$accessibility, _node$decorators2, _node$override, _node$readonly, _node$static, _node$declare, _node$returnType, _node$typeParameters, _node$optional2, _node$optional3, _node$accessibility2, _node$readonly2, _node$static2, _node$
  32. line length 638 characters (raw pass, confidence 0.50)

        exports2.default = /((['"])(?:(?!\2|\\).|\\(?:\r\n|[\s\S]))*(\2)?|`(?:[^`\\$]|\\[\s\S]|\$(?!\{)|\$\{(?:[^{}]|\{[^}]*\}?)*\}?)*(`)?)|(\/\/.*)|(\/\*(?:[^*]|\*(?!\/))*(\*\/)?)|(\/(?!\*)(?:\[(?:(?![\]\\]).|\\.)*\]|(?![\/\]\\]).|\\.)+\/(?:(?!\s*(?:\b|[\u0080-\uFFFF$\\'"~({]|[+\-!](?!=)|\.?\d))|[gmiyus]{1,6}\b(?![\u0080-
  33. info warn → info by review long-line lib/transform/babelBundle.js:49254:1

    line length 7125 characters (raw pass, confidence 0.65)

        module2.exports.ID_Start = /[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u06
    likely benign LLM, confidence 0.95 A large regex of Unicode ID_Start ranges in a bundled library.
    Reasoning

    This is a large regex character class encoding the Unicode ID_Start property, a standard data table in identifier-handling libraries.

  34. info warn → info by review long-line lib/transform/babelBundle.js:49255:1

    line length 8583 characters (raw pass, confidence 0.65)

        module2.exports.ID_Continue = /[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u
    likely benign LLM, confidence 0.95 A large regex of Unicode ID_Continue ranges in a bundled library.
    Reasoning

    This is a large regex character class for the Unicode ID_Continue property, the counterpart to ID_Start, and is standard library data.

  35. line length 738 characters (raw pass, confidence 0.50)

        var a = { c: { longName: "chrome" }, ca: { longName: "chrome_android" }, e: { longName: "edge" }, f: { longName: "firefox" }, fa: { longName: "firefox_android" }, s: { longName: "safari" }, si: { longName: "safari_ios" }, o: { longName: "opera", engine: "Blink" }, oa: { longName: "opera_android", engine: "Blink" },
  36. line length 664 characters (raw pass, confidence 0.50)

          let g = null != e2 ? e2 : {}, q = { listAllCompatibleVersions: null !== (s2 = g.listAllCompatibleVersions) && void 0 !== s2 && s2, includeDownstreamBrowsers: null !== (o2 = g.includeDownstreamBrowsers) && void 0 !== o2 && o2, widelyAvailableOnDate: null !== (f2 = g.widelyAvailableOnDate) && void 0 !== f2 ? f2 : v
  37. line length 681 characters (raw pass, confidence 0.50)

              e3.setMonth(e3.getMonth() - 2), n2 > e3 && (null != a2 ? a2 : 1787873932909) < e3.getTime() && (console.warn("[baseline-browser-mapping] The data in this module is over two months old and you are targetting a recent feature cut off date of " + n2.toISOString().slice(0, 10) + ". To ensure accurate Baseline dat
  38. line length 2949 characters (mostly string/comment) (raw pass, confidence 0.39)

        module2.exports = { "0": "116", "1": "117", "2": "118", "3": "119", "4": "120", "5": "121", "6": "122", "7": "123", "8": "124", "9": "125", A: "10", B: "11", C: "12", D: "7", E: "8", F: "9", G: "15", H: "80", I: "151", J: "4", K: "27", L: "6", M: "13", N: "14", O: "16", P: "17", Q: "18", R: "79", S: "81", T: "83", 
  39. info warn → info by review long-line lib/transform/babelBundle.js:53869:1

    line length 31391 characters (raw pass, confidence 0.65)

        module2.exports = { A: { A: { L: 0, D: 0, E: 0, F: 0, A: 0, B: 0.266336, AD: 0 }, B: "ms", C: ["", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "
    likely benign LLM, confidence 0.93 A very large static browser-compatibility data object from caniuse-lite.
    Reasoning

    This is a caniuse-lite browser compatibility data object embedded in the bundle. It is plain static data with no executable logic, so the length is expected.

  40. line length 19244 characters (mostly string/comment) (raw pass, confidence 0.39)

        module2.exports = { "0": "_I _IB", "1": "_d ZD", "2": "_qS _uI", "3": "_4 _e", "4": "J jB", "5": "B C", "6": "_Y _RF", "7": "_vS _qI", "8": "_BE _AB", "9": "gD _AB", A: "A B", B: "D A", C: "FE GE", D: "_DE _aP", E: "_PC AD", F: "J _U", G: "_FD _rS", H: "_NC _JP", I: "_v _UB", J: "_YH _tI", K: "_H _tI", L: "FD GD", 
  41. info warn → info by review dynamic-import lib/transform/babelBundle.js:54747:23

    `require` called with a non-literal specifier (ast pass, confidence 0.60)

            }
            var queries = require(require.resolve(name, { paths: [".", ctx.path] }));
            if (typeof queries === "object" && queries !== null && queries.__esModule) {
              queries = queries.default;
    likely benign LLM, confidence 0.85 Browserslist's dynamic require of a resolved query module.
    Reasoning

    This is browserslist's config loader resolving a package path via require.resolve with explicit search paths, which is the library's intended way to load shared configs. The specifier is not attacker-controlled input in a suspicious way, so this is a legitimate dynamic require.

  42. info warn → info by review dynamic-import lib/transform/babelBundle.js:54767:21

    `require` called with a non-literal specifier (ast pass, confidence 0.60)

            }
            var stats = require(
              // Use forward slashes for module paths, also on Windows.
              require.resolve(path.posix.join(name, "browserslist-stats.json"), {
    likely benign LLM, confidence 0.85 Browserslist's dynamic require of its browserslist-stats.json data file.
    Reasoning

    This dynamic require resolves browserslist-stats.json from the user's own package path, a documented browserslist feature. It is a normal non-literal require pattern.

  43. info warn → info by review dynamic-import lib/transform/babelBundle.js:54817:26

    `require` called with a non-literal specifier (ast pass, confidence 0.80)

              try {
                compressed = require("caniuse-lite/data/regions/" + code + ".js");
              } catch (e) {
                throw new BrowserslistError("Unknown region name `" + code + "`.");
    likely benign LLM, confidence 0.85 Browserslist loads a caniuse-lite regional data file by name.
    Reasoning

    The require concatenates a region code into a caniuse-lite data path inside a try block, a common data-loading pattern. The code is validated by a surrounding error message and the target is a fixed data directory.

  44. info warn → info by review dynamic-import lib/transform/babelBundle.js:54836:24

    `require` called with a non-literal specifier (ast pass, confidence 0.80)

            try {
              compressed = require("caniuse-lite/data/features/" + name + ".js");
            } catch (e) {
              throw new BrowserslistError("Unknown feature name `" + name + "`.");
    likely benign LLM, confidence 0.85 Browserslist loads a caniuse-lite feature data file by name.
    Reasoning

    This is the same caniuse-lite feature-data loader pattern, with a fixed data directory prefix and a thrown error on failure. It is a legitimate lookup, not a payload fetch.

  45. info warn → info by review dynamic-execution lib/transform/babelBundle.js:60803:40

    `atob` decodes a base64 value at runtime — common step before dynamic fetch or eval (ast pass, confidence 0.75)

        function decodeBase64WithAtob(base64) {
          return decodeURIComponent(escape(atob(base64)));
        }
        function stripComment(sm) {
    likely benign LLM, confidence 0.85 A helper that decodes a base64 string via atob, used for inline source-map handling.
    Reasoning

    The function decodes base64 with atob and then decodeURIComponent, the standard way to read inline base64 source maps in source-map tooling. The decoded data is not executed, and the snippet shows no eval or fetch.

  46. info dynamic-execution lib/transform/babelBundle.js:60865:14

    `btoa` encodes a value as base64 at runtime — used in exfiltration patterns (ast pass, confidence 0.55)

          var json = this.toJSON();
          return btoa(unescape(encodeURIComponent(json)));
        }
        Converter.prototype.toURI = function() {
  47. info warn → info by review dynamic-import lib/transform/babelBundle.js:62117:14

    dynamic `import(...)` with a non-literal specifier (ast pass, confidence 0.65)

        module2.exports = function import_(filepath) {
          return import(filepath);
        };
      }
    likely benign LLM, confidence 0.80 A bundled Babel helper that wraps a dynamic import of a caller-supplied file path.
    Reasoning

    This is the standard dynamic-import helper emitted by Babel's bundling of CommonJS interop. It takes a filepath argument from its caller, which is normal for a config or plugin loader. Nothing in the snippet fetches remote content or decodes data.

  48. line length 529 characters (raw pass, confidence 0.50)

              if (parentParentPath.node.type === "AssignmentExpression" && parentParentPath.node.left === parentPath.node || parentParentPath.node.type === "UpdateExpression" || parentParentPath.node.type === "RestElement" || parentParentPath.node.type === "ArrayPattern" || parentParentPath.node.type === "ObjectProperty" &
  49. line length 712 characters (raw pass, confidence 0.50)

              path.replaceWithMultiple([_core.types.variableDeclaration("let", [_core.types.variableDeclarator(_core.types.cloneNode(classOuterBindingLocal)), _core.types.variableDeclarator(classOuterBindingDelegateLocal)]), _core.types.blockStatement([_core.types.variableDeclaration("let", [_core.types.variableDeclarator(
  50. line length 737 characters (raw pass, confidence 0.50)

              acc.push(_core.types.assignmentExpression("=", _core.types.cloneNode(descriptor), _core.types.callExpression(state.addHelper("applyDecoratedDescriptor"), [_core.types.cloneNode(target), _core.types.cloneNode(property), _core.types.arrayExpression(decorators.map((dec) => _core.types.cloneNode(dec.expression)))
  51. info warn → info by review dynamic-import lib/transform/babelBundle.js:72469:52

    `require` called with a non-literal specifier (ast pass, confidence 0.60)

          ...plugins,
          ...pluginsEpilogue.map(([name, options]) => [require(name), options])
        ],
        compact: false,
    likely benign LLM, confidence 0.80 Resolves Babel plugin names from a configuration list via require.
    Reasoning

    The require is inside a map over pluginsEpilogue entries of [name, options], which is how Babel resolves plugin names from configuration. Loading a named plugin is expected behaviour for a transpiler, and the snippet shows no decoding or network activity.

  52. info warn → info by review long-line lib/transform/esmLoader.js:2302:1

    line length 7125 characters (raw pass, confidence 0.65)

        module2.exports.ID_Start = /[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u06
    dismissed LLM, confidence 0.92 A generated Unicode ID_Start character-class regex on one long line.
    Reasoning

    This is a very long regex literal encoding the Unicode ID_Start property table, a common output of generated Unicode data files. Its length is expected and it contains no executable behaviour.

  53. info warn → info by review long-line lib/transform/esmLoader.js:2303:1

    line length 8583 characters (raw pass, confidence 0.65)

        module2.exports.ID_Continue = /[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u
    dismissed LLM, confidence 0.92 A generated Unicode ID_Continue character-class regex on one long line.
    Reasoning

    Same as the ID_Start finding: this is a generated Unicode ID_Continue regex table. Long lines are typical of minified or generated data and this is not obfuscation of logic.

  54. info warn → info by review dynamic-import lib/transform/esmLoader.js:7880:30

    `require` called with a non-literal specifier (ast pass, confidence 0.60)

      process.env.BROWSERSLIST_IGNORE_OLD_DATA = "true";
      const { babelTransform } = require((0, import_package2.libPath)("transform", "babelBundle"));
      const babelResult = babelTransform(originalCode, filename, !!moduleUrl, pluginsEpilogue, useDefineForClassFields, jsx);
      if (!babelResult?.code)
    likely benign LLM, confidence 0.80 Loads the package's own babelBundle module via a computed path.
    Reasoning

    The specifier is a path built by libPath from fixed internal arguments ('transform', 'babelBundle'), so it is an internal module load rather than attacker-controlled input. The surrounding code is a normal transform step.

  55. info critical → info by review dynamic-execution lib/transform/esmLoader.js:7897:29

    `eval` called with a non-literal expression (ast pass, confidence 0.90)

        const fileName = import_url2.default.pathToFileURL(file);
        const esmImport = () => eval(`import(${JSON.stringify(fileName)})`);
        if (loaderChannel) {
    likely benign LLM, confidence 0.70 Uses eval to perform a native dynamic import of a local module path.
    Reasoning

    This is a known loader technique for forcing a native dynamic import from CommonJS, used by tools such as ts-node and tsx. The path is JSON.stringify-escaped, so it is not an injection vector, and the file is a local module being loaded. The use of eval is unusual and worth a note, but the purpose is legitimate.

  56. info critical → info by review dynamic-execution lib/transform/esmLoader.js:7899:13

    `eval` called with a non-literal expression (ast pass, confidence 0.90)

        if (loaderChannel) {
          await eval(`import(${JSON.stringify(fileName + ".esm.preflight")})`).catch((error) => debugTest("Failed to load preflight for " + file + ", source maps may be missing for errors thrown during loading.", error)).finally(nextTask);
        }
        return await esmImport().finally(nextTask);
    likely benign LLM, confidence 0.70 Uses eval to dynamically import an optional preflight file next to a loaded module.
    Reasoning

    This evaluates a dynamic import of a sibling '.esm.preflight' file derived from the local module path, JSON.stringify-escaped and wrapped in a catch that logs failures. It follows the same legitimate loader pattern, though the eval use is unusual.

  57. info warn → info by review dynamic-import lib/transform/esmLoader.js:7903:18

    `require` called with a non-literal specifier (ast pass, confidence 0.60)

      }
      const result = require(file);
      const depsCollector = currentFileDepsCollector();
      if (depsCollector) {
    likely benign LLM, confidence 0.80 Requires the target module file inside a loader that also tracks dependencies.
    Reasoning

    This is a plain require of the file being loaded, which is the normal way a module loader executes a user's module or config. The following lines collect dependencies, which is ordinary loader bookkeeping.

  58. info whitespace-anomaly lib/worker/workerProcessEntry.js:9:1

    file mixes tab and space indentation (1 tab-indented and 1716 space-indented lines) (raw pass, confidence 0.40)

    var __copyProps = (to, from, except, desc) => {
      if (from && typeof from === "object" || typeof from === "function") {
        for (let key of __getOwnPropNames(from))
          if (!__hasOwnProp.call(to, key) && key !== except)
  59. line length 833 characters (raw pass, confidence 0.50)

        const snapshotPath = template.replace(/\{(.)?testDir\}/g, "$1" + this.project.testDir).replace(/\{(.)?snapshotDir\}/g, "$1" + this.project.snapshotDir).replace(/\{(.)?snapshotSuffix\}/g, this.snapshotSuffix ? "$1" + this.snapshotSuffix : "").replace(/\{(.)?testFileDir\}/g, "$1" + parsedRelativeTestFilePath.dir).rep
  60. info long-line types/test.d.ts:7632:1

    line length 560 characters (raw pass, confidence 0.50)

      video: VideoMode | /** deprecated */ 'retry-with-video' | { mode: VideoMode, size?: ViewportSize, fps?: number, show?: { actions?: { duration?: number, position?: 'top-left' | 'top' | 'top-right' | 'bottom-left' | 'bottom' | 'bottom-right', /** @deprecated Use `style.title` instead. */ fontSize?: number, cursor?: 'no

Reproduce This Scan

Run disclude locally to verify. These commands scan the published file; the "new in this release" marks come from comparing it with the previous release's file, which they don't repeat. Add --format sarif for SARIF output. Add --llm (with an API key in the environment) to include the LLM review.

cargo install disclude --version 4.3.0
curl -fsSL -o playwright-1.65.0-alpha-2026-10-23.tgz https://registry.npmjs.org/playwright/-/playwright-1.65.0-alpha-2026-10-23.tgz
printf '%s  %s\n' 39ef36d9e0b8efafe5b868d210e31caa043ba89a6102a30e218c11a2e11cc678 playwright-1.65.0-alpha-2026-10-23.tgz | shasum -a 256 -c -
mkdir pkg && tar -xzf playwright-1.65.0-alpha-2026-10-23.tgz -C pkg --strip-components 1
disclude scan --untrusted --severity info pkg