microsoft/playwright · error · Error
Trace entry '${entry}' escapes output directory
Error message
Trace entry '${entry}' escapes output directory What it means
Thrown by extractTrace() when a zip entry inside a .trace.zip file would, when joined with the output directory, resolve to a path outside that directory (resolveWithinRoot returns null). This is a path-traversal / 'zip-slip' guard: a maliciously or corruptly crafted trace archive could otherwise write files anywhere on disk during extraction.
Source
Thrown at packages/playwright-core/src/tools/trace/traceParser.ts:91
const resolved = resolveWithinRoot(this._dir, entryName);
if (!resolved)
return;
try {
const buffer = await fs.promises.readFile(resolved);
return new Blob([new Uint8Array(buffer)]);
} catch {
}
}
}
export async function extractTrace(traceFile: string, outDir: string): Promise<void> {
const zipFile = new ZipFile(traceFile);
try {
const entries = await zipFile.entries();
for (const entry of entries) {
const outPath = resolveWithinRoot(outDir, entry);
if (!outPath)
throw new Error(`Trace entry '${entry}' escapes output directory`);
await fs.promises.mkdir(path.dirname(outPath), { recursive: true });
const buffer = await zipFile.read(entry);
await fs.promises.writeFile(outPath, buffer);
}
} finally {
zipFile.close();
}
}
View on GitHub (pinned to c8fc3bf8d3)
Solutions
- Re-export the trace from the original Playwright run; do not use a hand-modified archive.
- If you received the trace from an untrusted source, treat it as untrusted and do not extract it.
- Inspect the archive entry names (unzip -l) for '../' or leading slashes and repackage it without traversal sequences if you control the source.
Example fix
// inspect offending entries unzip -l trace.zip | grep '\.\./' // regenerate from source npx playwright test --trace=on
Defensive patterns
Strategy: validation
Validate before calling
import path from 'path';
function entriesAreSafe(entries: string[], outDir: string): boolean {
const root = path.resolve(outDir);
return entries.every(e => {
if (path.isAbsolute(e)) return false;
const resolved = path.resolve(root, e);
return resolved === root || resolved.startsWith(root + path.sep);
});
} Type guard
function isSafeEntryName(entry: string): boolean {
return !path.isAbsolute(entry) && !entry.includes('..');
} Try / catch
try {
await extractTrace(traceFile, outDir);
} catch (e) {
if (/escapes output directory/.test((e as Error).message)) {
console.warn('Refusing to extract unsafe trace archive:', traceFile);
}
throw e;
} Prevention
- Only extract trace archives produced by Playwright itself.
- Treat third-party or downloaded trace zips as untrusted input.
- Run extraction in a sandbox/throwaway directory so traversal cannot reach sensitive paths.
When it happens
Trigger: Opening/extracting a trace archive whose internal entry names contain '../' sequences or absolute paths, e.g. an entry named '../../../etc/passwd'. Can also occur with archivers that emit absolute entry names.
Common situations: A hand-edited or third-party-supplied trace zip; a corrupted download; an archive produced by a tool that stores absolute paths. In normal Playwright-generated traces this should never happen.
Related errors
- Attachment name '${fileName}' escapes output directory
- HAR zip entry '${entry}' escapes output directory
- Download filename '${downloadFilename}' escapes download dir
- HAR entry _file escapes base directory: ${file}
- File access denied: ${resolvedFilename} is outside allowed r
AI-assisted analysis of microsoft/playwright@c8fc3bf8d3 (2026-08-12).
Data as JSON: /api/errors/522a1ad4b046034a.
Report an issue: GitHub.