upstash/context7 · warning
Skipping file with unsafe path
Error message
Skipping file with unsafe path: ${item.path} What it means
downloadSkillTree strips the skill path prefix from each file and rejects any relative path containing "..", which would allow directory traversal outside the intended skill directory. The file is skipped with this warning instead of being written. This is a deliberate security guard, not a bug in the library.
Solutions
- Inspect the reported item.path in the source repo; remove or rename the offending file.
- Verify the skillPath argument exactly matches the directory prefix used in the GitHub tree.
- Only download skill trees from trusted repositories.
- If the file is legitimate, restructure it so it lives inside the skill directory instead of using ../ escapes.
Example fix
// before
await downloadSkillTree({ repo: 'untrusted-skills', skillPath: 'skills/foo' });
// after
await downloadSkillTree({ repo: 'trusted-skills', skillPath: 'skills/foo' }); // and ensure skillPath matches tree paths Defensive patterns
Strategy: validation
Validate before calling
function isSafeRelativePath(p) { return !p.split('/').includes('..') && !p.startsWith('/') && p.length > 0; }
if (!isSafeRelativePath(relativePath)) skip(item); Type guard
const isSafeSkillPath = (p: string): p is string => !p.includes('..'); Prevention
- Only download skills from trusted repositories.
- Ensure skillPath exactly matches the tree directory prefix.
- Normalize and validate paths before writing files to disk.
- Review the source repo if this warning appears repeatedly.
When it happens
Trigger: A GitHub tree entry whose path, after slicing off the skillPath prefix, contains ".." — i.e. the remote repo contains a file whose path escapes the skill directory (malicious repo, symlink-like naming, or a skillPath that doesn't actually prefix item.path).
Common situations: Downloading skills from an untrusted third-party repo; passing a skillPath that doesn't match the tree paths so slice() produces odd strings; hostile repos crafted to overwrite local files.
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 file path " " resolves outside the target directory
- Skill name " " escapes the skills root
- Unsafe skill name
- Context7 base URL must not contain credentials
- downloadData.error || "no files"
AI-assisted analysis of upstash/context7@4416fb855b (2026-09-16).
Data as JSON: /api/errors/4e092c931b1a1820.
Report an issue: GitHub.
Appendix: source
Thrown at packages/cli/src/utils/github.ts:295
return { files: [], error: `No files found in ${skillPath}` };
}
const files: SkillFile[] = [];
for (const item of skillFiles) {
const rawUrl = `${GITHUB_RAW}/${owner}/${repo}/${branch}/${item.path}`;
const fileResponse = await fetch(rawUrl, { headers: ghHeaders });
if (!fileResponse.ok) {
console.warn(`Failed to fetch ${item.path}: ${fileResponse.status}`);
continue;
}
const content = await fileResponse.text();
const relativePath = item.path.slice(skillPath.length + 1);
// Reject paths that attempt directory traversal
if (relativePath.includes("..")) {
console.warn(`Skipping file with unsafe path: ${item.path}`);
continue;
}
files.push({
path: relativePath,
content,
});
}
return { files };
}
async function downloadSingleSkillFile(
skillUrl: string,
ghHeaders: Record<string, string>
): Promise<SkillFile[] | null> {
let fileName: string;
try {View on GitHub (pinned to 4416fb855b)