heygen-com/hyperframes · critical · Error

Unsafe target "${target}": path segments may not contain "..

Error message

Unsafe target "${target}": path segments may not contain "..".

What it means

Thrown by assertSafeTarget when a registry file target contains a '..' path segment. The regex matches '..' between separators or at the start/end, catching both Unix and Windows backslash traversal attempts. This blocks escapes like '../../etc' that would resolve outside destDir.

Source

Thrown at packages/cli/src/registry/installer.ts:99

  onDisk: Buffer | string,
): boolean {
  const installed = record[target];
  if (!installed) return true;
  return installed !== digest(onDisk);
}

/**
 * Reject target paths that would escape `destDir`. Mirrors the pattern check
 * in `packages/core/schemas/registry-item.json#files.items.target`, but runs at
 * install time so a registry that bypasses schema validation still can't write
 * outside the project.
 */
export function assertSafeTarget(destDir: string, target: string): void {
  if (isAbsolute(target)) {
    throw new Error(`Unsafe target "${target}": absolute paths are not allowed.`);
  }
  if (/(^|[/\\])\.\.([/\\]|$)/.test(target)) {
    throw new Error(`Unsafe target "${target}": path segments may not contain "..".`);
  }
  if (/^[A-Za-z]:[/\\]/.test(target)) {
    throw new Error(`Unsafe target "${target}": Windows drive letters are not allowed.`);
  }
  const resolved = resolve(destDir, target);
  const rel = relative(resolve(destDir), resolved);
  if (rel.startsWith("..") || isAbsolute(rel)) {
    throw new Error(`Unsafe target "${target}": resolves outside destDir ${destDir}.`);
  }
}

function isInstalledRegistryBlockComposition(item: RegistryItem, file: FileTarget): boolean {
  return (
    item.type === "hyperframes:block" &&
    file.type === "hyperframes:composition" &&
    file.target.toLowerCase().endsWith(".html")
  );
}

View on GitHub (pinned to c2996c8626)

Solutions

  1. Flatten the target so it stays within destDir (no '..' segments)
  2. If sharing across projects is intended, install the asset into each project separately
  3. Validate targets against the registry-item.json schema before publishing
  4. Audit the item's file list before installing

Example fix

// before
{ "target": "../../shared/x.html" }
// after
{ "target": "shared/x.html" }
Defensive patterns

Strategy: validation

Validate before calling

function noTraversal(target: string): boolean {
  return !/(^|[/\\])\.\.([/\\]|$)/.test(target);
}

Type guard

function isNonTraversalTarget(target: string): boolean {
  return !/(^|[/\\])\.\.([/\\]|$)/.test(target);
}

Prevention

When it happens

Trigger: assertSafeTarget runs during install; target matches /(^|[/\\])\.\.([/\\]|$)/ (e.g. '../secret', 'a/../../b', '..\\windows') → throw at installer.ts:99.

Common situations: A registry item trying to (or accidentally) write above the project root; cross-platform targets mixing '/' and '\'; an item authored to 'share' a file with a sibling project via relative traversal; a malicious registry.

Related errors


AI-assisted analysis of heygen-com/hyperframes@c2996c8626 (2026-08-12). Data as JSON: /api/errors/54cf06bee285f69b. Report an issue: GitHub.