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

playwright 1.65.0-alpha-2026-10-21

Source
https://github.com/microsoft/playwright
Commit scanned
66070a1eaa0b (recorded by npm)
Directory
packages/playwright (only this part of the repository was scanned)
Compared with
27219bd2cc94 (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-21 06:26

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.95 Base64 decoding of test stdio chunks with a Buffer-or-atob fallback.
    Reasoning

    The atob call is a fallback for browser environments where Buffer is unavailable, decoding base64 stdio chunks from the Playwright test runner. It feeds data into a plain string chunk and is not executed or fetched, so it is ordinary data handling.

  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.93 Loads the package's own package.json via a computed path.
    Reasoning

    The require target is path.join of the package root and the fixed filename package.json. The specifier is non-literal only because of path construction, and it reads the project's own metadata.

  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.93 Loads istanbul coverage libraries resolved from the config directory.
    Reasoning

    The module is resolved with require.resolve from the configured directory and limited to fixed istanbul package names. This is a standard way to load optional peer dependencies.

  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.93 Loads istanbul-lib-report via a resolved path.
    Reasoning

    Same pattern as the adjacent line: a fixed istanbul-lib-report name is resolved from the config directory and then required. No attacker-controlled input is involved.

  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.93 Loads istanbul-reports via a resolved path.
    Reasoning

    The istanbul-reports package is resolved from a fixed name and required, matching the other coverage dependency loads in this function.

  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.88 Requires internal Babel plugins by name from a configured list.
    Reasoning

    The plugin names come from Playwright's own internal epilogue list of Babel plugins, not from untrusted input. Requiring configured Babel plugins by name is standard practice.

  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 Loads the internal babelBundle module via libPath.
    Reasoning

    The require path is built from libPath with fixed segments to load Playwright's own babelBundle module. It is an internal bundling split rather than a dropper.

  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.85 Eval-wrapped dynamic import of a local file URL to preserve native ESM loading.
    Reasoning

    The eval wraps a dynamic import with the file URL serialized through JSON.stringify. This is a known idiom to keep the import() call from being downleveled to require by the TypeScript build. The argument is a local test file path, so the eval is not run on attacker-controlled code.

  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.85 Eval-wrapped dynamic import of an ESM preflight module for a local test file.
    Reasoning

    This is the same eval-wrapped import idiom, loading a '.esm.preflight' companion of a local test file for source map handling. The string is built from a local path and JSON-escaped, and the error is caught and logged.

  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 Playwright runner.
    Reasoning

    The require loads the user's test file, which is the core purpose of a test runner. The dependency collector wraps this load for tracking, so the non-literal specifier is expected.

  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 66070a1eaa0b869379607a9e0e1a652ddf2a77da
disclude scan --severity info --diff 27219bd2cc94e1ebceec58f188760a6bf458c192 packages/playwright