upstash/context7 · error
Skill file path " " resolves outside the target directory
Error message
Skill file path "${file.path}" resolves outside the target directory What it means
Thrown by installSkillFiles as a directory-traversal guard: after resolving a skill file's target path, the resolved path must stay inside skillDir (equal to it or nested under it with either separator). If a file entry's declared path escapes the skill directory — via `..` segments, absolute paths, or symlinks resolved earlier — installation aborts to prevent writing arbitrary files outside the skill target.
Solutions
- Fix the `path` fields in the skill manifest to be relative paths staying inside the skill directory (e.g. "scripts/run.sh")
- Remove `..` segments and absolute paths from file entries
- Only install skills from trusted sources — this error may indicate a malicious or corrupted manifest
- If the file legitimately belongs elsewhere, it should be installed by a different mechanism, not via the skill installer
Example fix
// before (manifest entry escapes target dir)
{ "path": "../../shared/helper.ts", "content": "..." }
// after
{ "path": "lib/helper.ts", "content": "..." } Defensive patterns
Strategy: validation
Validate before calling
import { resolve, sep } from "path";
function isInsideSkillDir(skillDir: string, relPath: string): boolean {
if (relPath.startsWith("/") || /^[A-Za-z]:/.test(relPath)) return false;
const filePath = resolve(skillDir, relPath);
return filePath === skillDir || filePath.startsWith(skillDir + sep);
}
files.filter(f => !isInsideSkillDir(skillDir, f.path)); // reject before install Type guard
function isSafeManifestPath(p: string): boolean {
return !p.startsWith("/") && !p.split("/").includes("..") && !p.includes("\\");
} Try / catch
try {
await installSkillFiles(skillDir, files);
} catch (e) {
if (e.message.includes("resolves outside the target directory")) {
console.error(`Skill manifest rejected (path traversal guard): ${e.message}`);
// do not retry; inspect the skill source for tampering
}
} Prevention
- Only install skills from trusted sources
- Keep manifest paths relative and free of `..` segments
- Lint skill manifests before distribution
When it happens
Trigger: Installing a skill whose file manifest contains entries like path: "../../../etc/cron.d/evil", an absolute path like "/Users/x/.zshrc", or any path that, after resolution, is not under skillDir.
Common situations: Downloading community skills from untrusted sources, hand-written skill manifests with typos in relative paths (e.g. too many `..`), or tools generating manifests with absolute output paths.
Understand the failure class
Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.
Related errors
- Skill name " " escapes the skills root
- Unsafe skill name
- Context7 base URL must not contain credentials
- Skipping file with unsafe path
- Context7 base URL must not contain a query string or…
AI-assisted analysis of upstash/context7@4416fb855b (2026-09-16).
Data as JSON: /api/errors/cc17720444a2bdfa.
Report an issue: GitHub.
Appendix: source
Thrown at packages/cli/src/utils/installer.ts:23
import { assertSkillNameInRoot } from "./skill-name.js";
export async function installSkillFiles(
skillName: string,
files: SkillFile[],
skillsRoot: string
): Promise<void> {
const skillDir = assertSkillNameInRoot(skillsRoot, skillName);
for (const file of files) {
const filePath = resolve(skillDir, file.path);
// Prevent directory traversal — resolved path must stay within skillDir
if (
!filePath.startsWith(skillDir + "/") &&
!filePath.startsWith(skillDir + "\\") &&
filePath !== skillDir
) {
throw new Error(`Skill file path "${file.path}" resolves outside the target directory`);
}
const fileDir = dirname(filePath);
await mkdir(fileDir, { recursive: true });
await writeFile(filePath, file.content);
}
}
export async function symlinkSkill(
skillName: string,
sourcePath: string,
skillsRoot: string
): Promise<void> {
const targetPath = assertSkillNameInRoot(skillsRoot, skillName);
try {
const stats = await lstat(targetPath);View on GitHub (pinned to 4416fb855b)