can1357/oh-my-pi · error · ArchiveError
Archive symlink escapes extraction dir: ${link.path} -> ${li
Error message
Archive symlink escapes extraction dir: ${link.path} -> ${link.target} What it means
extractArchive encountered a symlink entry whose raw target could not be normalized to an archive-root-relative path (normalizeArchiveLookupPath returned undefined), meaning the target escapes or is malformed beyond the library's containment rules. The library refuses to materialize symlinks that could resolve outside the extraction root.
Source
Thrown at packages/utils/src/ar/open.ts:213
for (const file of files) {
const extracted = await archive.readFile(file.path);
const outputPath = path.resolve(extractRoot, file.path);
await Bun.write(outputPath, extracted.bytes);
const permissions = (file.mode ?? 0) & 0o777;
if (permissions) await fs.chmod(outputPath, permissions);
count++;
}
for (const link of links) {
const outputPath = path.resolve(extractRoot, link.path);
// Reader link targets are archive-root-relative (raw targets survive
// only for links that escape the root, which cannot be materialized).
// Rewrite to a target relative to the link's own directory so the
// symlink resolves correctly on disk.
const normalizedTarget = normalizeArchiveLookupPath(link.target);
if (normalizedTarget === undefined) {
throw new ArchiveError(`Archive symlink escapes extraction dir: ${link.path} -> ${link.target}`);
}
const resolvedTarget = path.resolve(extractRoot, normalizedTarget);
if (resolvedTarget !== extractRoot && !resolvedTarget.startsWith(extractRoot + path.sep)) {
throw new ArchiveError(`Archive symlink escapes extraction dir: ${link.path} -> ${link.target}`);
}
await fs.mkdir(path.dirname(outputPath), { recursive: true });
await fs.symlink(path.relative(path.dirname(outputPath), resolvedTarget) || ".", outputPath);
count++;
}
return count;
}
View on GitHub (pinned to 9690622007)
Solutions
- List the archive's entries and rewrite offending symlink targets to archive-root-relative ones, then repack.
- Skip or drop symlink entries when extracting untrusted archives (many extractors have an option to ignore links).
- If the link is legitimately needed outside the root, create it manually after extraction with your own validated target.
- Treat the archive as hostile if it comes from an untrusted source and reject it.
Defensive patterns
Strategy: try-catch
Validate before calling
for (const e of entries) {
if (e.storage?.type === "link" && path.isAbsolute(e.storage.targetPath)) {
throw new Error(`absolute symlink target in archive: ${e.path} -> ${e.storage.targetPath}`);
}
} Try / catch
try {
await extractArchive(src, destRoot);
} catch (err) {
if (err instanceof ArchiveError && err.message.includes("symlink escapes")) {
// option: re-extract ignoring link entries
}
throw err;
} Prevention
- Pre-scan link entries and their targets before extracting untrusted archives.
- Prefer archives repacked without symlinks when distributing cross-platform.
- Never let archive links point outside the extraction root; rewrite them at packaging time.
- Treat absolute symlink targets as hostile in downloaded archives.
When it happens
Trigger: extractArchive iterating link entries where normalizeArchiveLookupPath(link.target) is undefined — e.g. a target with a scheme/absolute form or '..'-escaping segments the normalizer rejects — at the first check in open.ts before the resolved-target containment test.
Common situations: Archives (tar, cpio, etc.) containing absolute symlink targets like '/usr/lib/foo' or targets with '../' that climb above the archive root; maliciously crafted archives; archives produced on systems with different link conventions (e.g. Windows-style '|'-separated LZH links).
Related errors
- Archive entry escapes extraction dir: ${entry.path}
- ${scheme}:// path escapes its root: ${rawPath}
- {scheme}:// path escapes its root: {path}
- #{scheme}:// path escapes its root: #{path}
- local:// URL escapes local root
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/926970b27c01f33c.
Report an issue: GitHub.