vercel-labs/skills · error

Unsafe subpath: "${subpath}" contains path traversal segment

Error message

Unsafe subpath: "${subpath}" contains path traversal segments. Subpaths must not contain ".." components.

What it means

sanitizeSubpath() normalizes backslashes to slashes and rejects the whole subpath if any single '..' segment appears. It is the front-line guard in source parsing, so hostile or malformed source specs fail before any filesystem or network operation.

Source

Thrown at src/source-parser.ts:114

    // On error, return null to indicate we couldn't determine
    return null;
  }
}

/**
 * Sanitizes a subpath to prevent path traversal attacks.
 * Rejects subpaths containing ".." segments that could escape the repository root.
 * Returns the sanitized subpath, or throws if the subpath is unsafe.
 */
export function sanitizeSubpath(subpath: string): string {
  // Normalize to forward slashes for consistent handling
  const normalized = subpath.replace(/\\/g, '/');

  // Check each segment for ".."
  const segments = normalized.split('/');
  for (const segment of segments) {
    if (segment === '..') {
      throw new Error(
        `Unsafe subpath: "${subpath}" contains path traversal segments. ` +
          `Subpaths must not contain ".." components.`
      );
    }
  }

  return subpath;
}

/**
 * Check if a string represents a local file system path
 */
function isLocalPath(input: string): boolean {
  return (
    isAbsolute(input) ||
    input.startsWith('./') ||
    input.startsWith('../') ||
    input === '.' ||

View on GitHub (pinned to 435076e789)

Solutions

  1. Remove '..' segments (or the whole subpath) from the source string before parsing
  2. Use explicit, clean subpaths: 'owner/repo/path/to/skill'
  3. If traversal was unintentional, simplify to the direct path to the skill directory
  4. In SDKs, validate subpaths against /^[A-Za-z0-9._\/-]+$/ with no '..' component

Example fix

# before
skills add github.com/org/repo/skills/../skills/python
# after
skills add github.com/org/repo/skills/python
Defensive patterns

Strategy: validation

Validate before calling

function isSafeSubpath(sub: string): boolean {
  const n = sub.replace(/\\/g, '/');
  return !n.split('/').includes('..');
}
if (subpath && !isSafeSubpath(subpath)) throw new Error(`Unsafe subpath: ${subpath}`);

Type guard

function isUnsafeSubpath(e: unknown): e is Error {
  return e instanceof Error && /Unsafe subpath.*\.\./.test(e.message);
}

Try / catch

try { const src = parseSource(input); }
catch (e) {
  if (isUnsafeSubpath(e)) {
    const cleaned = input.replace(/\.{2}(?:\/[\\/]*)?/g, '').replace(/\\/g, '/');
    return parseSource(cleaned); // retry with sanitized input
  }
  throw e;
}

Prevention

When it happens

Trigger: parseSource() receiving a source string whose subpath component contains '..' — e.g. 'owner/repo/..', 'github.com/a/b/../../c', or Windows-style 'a\\..\\b'. Any '..' segment, even one that would stay inside, is rejected.

Common situations: Users pasting traversal-style relative paths; automation building source strings by concatenation without sanitizing; inputs mixing Windows backslash separators.

Related errors


AI-assisted analysis of vercel-labs/skills@435076e789 (2026-08-28). Data as JSON: /api/errors/fdbd329e86fad09d. Report an issue: GitHub.