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

playwright 1.65.0-alpha-2026-10-19

Source
https://github.com/microsoft/playwright
Commit scanned
b335271cdc2b (recorded by npm)
Directory
packages/playwright (only this part of the repository was scanned)
Compared with
b335271cdc2b (0 signals introduced since)
Files
132 scanned, 13 skipped (binary, oversized, or unrecognised)
Signals
0 critical · 0 warn · 12 info
Scan time
7.9 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-20 05: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.93 Base64 decoding of test stdout/stderr chunks in a browser-compatible fallback path.
    Reasoning

    atob decodes base64 stdio chunks from the test runner's own IPC messages when Buffer is unavailable. This is ordinary data handling with no fetch or eval following it in the snippet.

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

    The require specifier is path.join of the package root and 'package.json', a fixed local file. The non-literal specifier is only a result of the path construction and is not attacker-controlled.

  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 istanbul coverage libraries through require.resolve with a fixed name list.
    Reasoning

    The specifiers are fixed istanbul module names resolved relative to the configured directory with require.resolve. This is standard plugin/dependency loading.

  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 istanbul-lib-report through require.resolve.
    Reasoning

    Same pattern as the preceding line: fixed istanbul module names resolved from the config directory. Nothing in the snippet is user-controlled input reaching the specifier.

  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 istanbul-reports through require.resolve.
    Reasoning

    Fixed module name resolved relative to the config directory, consistent with normal reporter dependency loading.

  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 configuration.
    Reasoning

    Plugin names come from the project's own Babel configuration (pluginsEpilogue), so requiring them is the expected behavior of a Babel plugin loader. The specifier is not hidden or encoded.

  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 bundled Babel transform module via a helper path.
    Reasoning

    The specifier is libPath to a fixed bundled module 'babelBundle', so the path is static in practice and the dynamic form is only a packaging convenience.

  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.82 Uses eval to preserve a native dynamic import() of an ESM test file.
    Reasoning

    eval is used to emit a real dynamic import() of a file URL. Wrapping it in eval keeps the transpiler from rewriting import() into require() for ESM loading, which is a known, legitimate pattern. The interpolated value is a file path passed through JSON.stringify.

  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.82 Eval-wrapped dynamic import of an ESM preflight module with error handling.
    Reasoning

    Same eval-wrapped import() technique used to preflight the ESM loader for a file. The value is a JSON-escaped local path, and failures are 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 runner.
    Reasoning

    This loads the test file being run by the runner, which is the core purpose of the loader. The non-literal specifier reflects that it loads arbitrary user test files by design, not hidden obfuscation.

  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 b335271cdc2b57cac2be8ad37c5dd283ac6b8938
disclude scan --severity info --diff b335271cdc2b57cac2be8ad37c5dd283ac6b8938 packages/playwright