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

  1. Inspect the reported item.path in the source repo; remove or rename the offending file.
  2. Verify the skillPath argument exactly matches the directory prefix used in the GitHub tree.
  3. Only download skill trees from trusted repositories.
  4. 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

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


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)