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

During tar.gz extraction, symlinks are validated by resolving their LinkName relative to the entry's directory; if the resolved target lies outside the destination directory the extraction is aborted with InvalidOperationException. This prevents symlink-based escapes from the extraction root.

Solutions

  1. Re-download the archive from a trusted source.
  2. Inspect symlinks (tar -tvzf) and repack so link targets resolve inside the archive root.
  3. If you control packaging, avoid emitting symlinks with targets outside the staged directory.

Example fix

// before
// entry "link" -> "../../../etc/passwd"
// after
// repack: entry "link" -> "./data/file" (resolves inside destination)
Defensive patterns

Strategy: try-catch

Validate before calling

await using var stream = File.OpenRead(tarGzPath);
await using var gz = new GZipStream(stream, CompressionMode.Decompress);
using var tar = new TarReader(gz);
while (await tar.GetNextEntryAsync() is { } e)
{
    if (e.EntryType == TarEntryType.SymbolicLink)
    {
        var resolved = Path.GetFullPath(Path.Combine(destinationPath, e.LinkName));
        if (!resolved.StartsWith(Path.GetFullPath(destinationPath) + Path.DirectorySeparatorChar, StringComparison.Ordinal)) throw new InvalidOperationException($"Unsafe symlink: {e.Name} -> {e.LinkName}");
    }
}

Try / catch

try { await ArchiveHelper.ExtractAsync(tgzPath, dest, env, ct); }
catch (InvalidOperationException ex) when (ex.Message.Contains("Symlink")) { // reject archive with escaping symlink
}

Prevention

When it happens

Trigger: Extracting a tar.gz containing a symlink whose LinkName (e.g. '../../../outside' or an absolute path) resolves outside the destination directory.

Common situations: Malicious archives that pair in-bounds entries with out-of-bounds symlinks; archives copied from filesystem layouts where relative link targets pointed elsewhere; corrupted archives.

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/2aefac1528ce5e9f. Report an issue: GitHub.

Appendix: source

Thrown at src/Aspire.Cli/Utils/ArchiveHelper.cs:126

                    // Preserve Unix file permissions from tar entry
                    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)