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

playwright 1.65.0-alpha-2026-10-17

Source
https://github.com/microsoft/playwright
Commit scanned
6bbe2475ba79 (recorded by npm)
Directory
packages/playwright (only this part of the repository was scanned)
Compared with
034f230cc68b (0 signals introduced since)
Files
132 scanned, 13 skipped (binary, oversized, or unrecognised)
Signals
0 critical · 0 warn · 12 info
Scan time
8.8 s
LLM review
Reviewed by claude-haiku-5-5 (Anthropic): 10 of 10 warn and critical signals; 10 demoted to info.
Disclude version
4.0.0
Scanned (UTC)
2026-10-17 22:56

Signals

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

  1. info warn → info by review dynamic-execution packages/playwright/src/isomorphic/teleReceiver.ts:462:90

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

      private _onStdIO(type: JsonStdIOType, testId: string | undefined, resultId: string | undefined, data: string, isBase64: boolean) {
        const chunk = isBase64 ? ((globalThis as any).Buffer ? Buffer.from(data, 'base64') : atob(data)) : data;
        const test = testId ? this._tests.get(testId) : undefined;
    likely benign LLM, confidence 0.90 Decodes base64 test stdio payloads in the browser-compatible reporter receiver.
    Reasoning

    atob is used as a fallback to decode base64 stdio chunks sent by the test runner. It only runs when Buffer is unavailable, and the decoded data is output text, not fetched or evaluated. This is a routine decoding step.

  2. info warn → info by review dynamic-import packages/playwright/src/package.ts:22:28

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

    export const packageRoot = path.join(__dirname, '..');
    export const packageJSON = require(path.join(packageRoot, 'package.json'));
    
    export function libPath(...parts: string[]): string {
    likely benign LLM, confidence 0.92 Loads the package's own package.json via a computed path.
    Reasoning

    The require target is path.join of the package root and the literal 'package.json'. This reads the tool's own manifest, which is a standard pattern.

  3. info warn → info by review dynamic-import packages/playwright/src/reporters/coverage.ts:120:27

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

          const resolveFrom = (name: string) => 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.90 Loads the istanbul coverage library, resolved from the config directory.
    Reasoning

    The specifier comes from require.resolve for the fixed name 'istanbul-lib-coverage', resolved relative to the configured directory. The module name is hardcoded, so this is a normal optional-dependency load.

  4. info warn → info by review dynamic-import packages/playwright/src/reporters/coverage.ts:121: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.90 Loads the istanbul report library through a resolved path.
    Reasoning

    Same pattern as the previous line: a hardcoded module name resolved from the config directory for istanbul-lib-report.

  5. info warn → info by review dynamic-import packages/playwright/src/reporters/coverage.ts:122: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.90 Loads the istanbul reports module through a resolved path.
    Reasoning

    Same pattern: a fixed istanbul-reports module name resolved from the config directory. No attacker-controlled input is involved.

  6. info warn → info by review dynamic-import packages/playwright/src/transform/babelBundle.ts:169: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 Requires Babel plugins named in the project configuration.
    Reasoning

    Plugin names come from the user's own Babel/test configuration and are loaded by design. The variable specifier is expected for a plugin system, and the user controls the config.

  7. info warn → info by review dynamic-import packages/playwright/src/transform/transform.ts:259:74

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

    
      const { babelTransform }: { babelTransform: BabelTransformFunction } = require(libPath('transform', 'babelBundle'));
      const babelResult = babelTransform(originalCode, filename, !!moduleUrl, pluginsEpilogue, useDefineForClassFields, jsx);
      if (!babelResult?.code)
    likely benign LLM, confidence 0.90 Lazily loads the internal babelBundle transform module.
    Reasoning

    The module path is libPath of the fixed name 'transform/babelBundle', which is the package's own bundled transform module. This is an internal lazy load.

  8. info critical → info by review dynamic-execution packages/playwright/src/transform/transform.ts:286:29

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

        const fileName = url.pathToFileURL(file);
        const esmImport = () => eval(`import(${JSON.stringify(fileName)})`);
    
        // For ESM imports handled by the asynchronous loader, issue a preflight to populate
    likely benign LLM, confidence 0.80 Uses eval to issue a native dynamic import of the test file's URL.
    Reasoning

    eval is used to construct a dynamic import() so that the CJS-to-ESM compiler does not rewrite it into require. The only interpolated value is JSON.stringify of a file URL for a local test file, which is a known workaround and not an injection path. The eval pattern still warrants a look, though.

  9. info critical → info by review dynamic-execution packages/playwright/src/transform/transform.ts:293: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: any) => debugTest('Failed to load preflight for ' + file + ', source maps may be missing for errors thrown during loading.', error))
              .finally(nextTask);
    likely benign LLM, confidence 0.80 Uses eval to dynamically import an ESM preflight marker for a test file.
    Reasoning

    Same eval-wrapped import() trick, here for a preflight module path built from a local file name with JSON.stringify. The input is controlled by the runner, not untrusted data, so this is a deliberate loader workaround.

  10. info warn → info by review dynamic-import packages/playwright/src/transform/transform.ts:305:18

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

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

    The runner requires the test file it is loading. The path comes from the test discovery list, which is the core purpose of the loader. This is expected behavior.

  11. file mixes tab and space indentation (9 tab-indented and 112 space-indented lines) (raw pass, confidence 0.40)

    interface TsConfig {
      extends?: string;
      compilerOptions?: {
        baseUrl?: string;
  12. 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. 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.0.0
git clone https://github.com/microsoft/playwright playwright && cd playwright
git checkout 6bbe2475ba79174c3df5f28a435958ef0351d515
disclude scan --severity info --diff 034f230cc68b286055186f4d9783188536f2f3cf packages/playwright