shadcn-ui/ui · critical · Error

We found an unsafe file path "${locationField}" in the regis

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.

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)

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.