microsoft/aspire · error · InvalidOperationException

Symlink ' ' targets ' ' which resolves outside the…

Error message

Symlink '{entry.Name}' targets '{entry.LinkName}' which resolves outside the destination directory.

What it means

BundleService throws this while extracting a bundle archive when a symlink entry would resolve to a path outside the destination directory. It is a zip-slip style path traversal guard: after resolving the link target relative to the link's directory, the full path must remain inside the normalized destination. Throwing prevents an attacker-crafted bundle from writing files outside the extraction root.

Solutions

  1. Fix the bundle so symlink targets are relative and resolve inside the destination directory
  2. Inspect the bundle entries with an archive tool to find the offending symlink (entry.Name -> entry.LinkName)
  3. If you own bundle creation, rewrite absolute/parent-escaping link targets to relative paths within the archive

Example fix

// before (in bundle manifest): symlink target escaping root
entry.LinkName = "../../../../etc/passwd"
// after: relative target inside destination
entry.LinkName = "../lib/foo.so"
Defensive patterns

Strategy: validation

Validate before calling

var resolved = Path.GetFullPath(Path.Combine(dir, linkName));
if (!resolved.StartsWith(destRoot + Path.DirectorySeparatorChar) && resolved != destRoot)
    throw new InvalidOperationException("Symlink escapes destination directory");

Prevention

When it happens

Trigger: Extracting a bundle containing a symlink whose LinkName is absolute, or contains '..' segments, or otherwise resolves (via Path.GetFullPath) to a path outside normalizedDestination.

Common situations: Using a hand-edited or third-party bundle archive; bundles repacked with symlinks pointing to shared libraries outside the extraction dir; bundles moved between machines where relative link targets resolve differently.

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 microsoft/aspire@25830f84bd (2026-09-16). Data as JSON: /api/errors/a1d6bd2e3e281965. Report an issue: GitHub.

Appendix: source

Thrown at src/Aspire.Cli/Bundles/BundleService.cs:932

                    // Preserve Unix file permissions from tar entry (e.g., execute bit)
                    if (!environment.IsWindows() && entry.Mode != default)
                    {
                        File.SetUnixFileMode(fullPath, (UnixFileMode)entry.Mode);
                    }
                    break;

                case TarEntryType.SymbolicLink:
                    if (string.IsNullOrEmpty(entry.LinkName))
                    {
                        continue;
                    }
                    // Validate symlink target stays within the extraction directory
                    var linkTarget = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(fullPath)!, entry.LinkName));
                    if (!linkTarget.StartsWith(normalizedDestination + Path.DirectorySeparatorChar, StringComparison.Ordinal) &&
                        !linkTarget.Equals(normalizedDestination, StringComparison.Ordinal))
                    {
                        throw new InvalidOperationException($"Symlink '{entry.Name}' targets '{entry.LinkName}' which resolves outside the destination directory.");
                    }
                    var linkDir = Path.GetDirectoryName(fullPath);
                    if (linkDir is not null)
                    {
                        Directory.CreateDirectory(linkDir);
                    }
                    if (File.Exists(fullPath))
                    {
                        File.Delete(fullPath);
                    }
                    File.CreateSymbolicLink(fullPath, entry.LinkName);
                    break;
            }
        }
    }
}

View on GitHub (pinned to 25830f84bd)