shadcn-ui/ui · critical · Error

We found an unsafe file path

Error message

We found an unsafe file path "${locationField}" in the registry item. Installation aborted.

What it means

Thrown by validateFilesTarget when isSafeTarget(locationField, cwd) returns false for a file's target (or path if target is absent). isSafeTarget rejects null bytes, URL-encoded traversal, ".." sequences, control characters, Windows drive letters outside Windows, and absolute/relative paths that resolve outside the project cwd. This is the security gate before any registry file is written to disk.

Solutions

  1. Inspect the registry item's file.target and file.path values printed in the message; remove any "..", encoded sequences, null bytes, or drive letters.
  2. If you control the registry, set target to a path inside the project (e.g. "@/lib/utils" or a relative path within cwd).
  3. If the registry is third-party, do not install it; report the unsafe path to its maintainer.
  4. Re-run the add command after the registry is fixed.

Example fix

// registry item (before)
{ "path": "utils.ts", "target": "../../etc/secret", "type": "registry:lib" }
// after
{ "path": "utils.ts", "type": "registry:lib" }
Defensive patterns

Strategy: validation

Validate before calling

import { isSafeTarget } from "@shadcn/utils" // or replicate the function
for (const f of files) {
  const loc = f.target ?? f.path
  if (loc && !isSafeTarget(loc, cwd)) {
    throw new Error(`unsafe target: ${loc}`)
  }
}

Type guard

function isSafeRelativeTarget(target: string, cwd: string): boolean {
  if (target.includes("\0") || target.includes("..")) return false
  const resolved = path.resolve(cwd, target)
  return resolved === cwd || resolved.startsWith(cwd + path.sep)
}

Try / catch

try {
  validateFilesTarget(tree.files ?? [], cwd)
} catch (e) {
  if (e instanceof Error && /unsafe file path/.test(e.message)) {
    // abort install, report the offending registry
  }
}

Prevention

When it happens

Trigger: During add/install, for each file in the resolved tree the locationField = file.target ?? file.path is tested. A target like "../../etc/passwd", "%2e%2e/escape", "~/../x", or one containing \0 fails isSafeTarget and aborts installation.

Common situations: A malicious or buggy registry item ships a target/path that tries to write outside the project; URL-encoded traversal in a copied path; a target that accidentally contains ".."; cross-platform paths with drive letters run on macOS/Linux.

Related errors


AI-assisted analysis of shadcn-ui/ui@efac598707 (2026-08-12). Data as JSON: /api/errors/d26a5228f9eb1504. Report an issue: GitHub.

Appendix: source

Thrown at packages/shadcn/src/utils/add-components.ts:466

      component.type === "registry:base"
  )
}

export function validateFilesTarget(
  files: z.infer<typeof registryItemFileSchema>[],
  cwd: string
) {
  for (const file of files) {
    // `target` decides the write location when present; otherwise the path is
    // derived from `file.path` (see resolveFilePath in update-files.ts). Both
    // are registry-controlled, so validate whichever one is used.
    const locationField = file?.target ?? file?.path
    if (!locationField) {
      continue
    }

    if (!isSafeTarget(locationField, cwd)) {
      throw new Error(
        `We found an unsafe file path "${locationField}" in the registry item. Installation aborted.`
      )
    }
  }
}

View on GitHub (pinned to efac598707)