{"record":{"id":"7635c654c5304899","repo":"microsoft/aspire","slug":"tar-entry-entry-name-would-extract-outside-the-destination-7635c6","errorCode":null,"errorMessage":"Tar entry '{entry.Name}' would extract outside the destination directory.","messagePattern":"Tar entry '(.+?)' would extract outside the destination directory\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Cli/Utils/ArchiveHelper.cs","lineNumber":92,"sourceCode":"\n        await using var fileStream = new FileStream(archivePath, FileMode.Open, FileAccess.Read);\n        await using var gzipStream = new GZipStream(fileStream, CompressionMode.Decompress);\n        await using var tarReader = new TarReader(gzipStream);\n\n        while (await tarReader.GetNextEntryAsync(cancellationToken: cancellationToken).ConfigureAwait(false) is { } entry)\n        {\n            if (string.IsNullOrEmpty(entry.Name))\n            {\n                continue;\n            }\n\n            var fullPath = Path.GetFullPath(Path.Combine(destinationPath, entry.Name));\n\n            // Guard against path traversal attacks (e.g., entries containing \"..\" segments)\n            if (!fullPath.StartsWith(normalizedDestination + Path.DirectorySeparatorChar, StringComparison.Ordinal) &&\n                !fullPath.Equals(normalizedDestination, StringComparison.Ordinal))\n            {\n                throw new InvalidOperationException($\"Tar entry '{entry.Name}' would extract outside the destination directory.\");\n            }\n\n            switch (entry.EntryType)\n            {\n                case TarEntryType.Directory:\n                    Directory.CreateDirectory(fullPath);\n                    break;\n\n                case TarEntryType.RegularFile:\n                    var dir = Path.GetDirectoryName(fullPath);\n                    if (dir is not null)\n                    {\n                        Directory.CreateDirectory(dir);\n                    }\n                    await entry.ExtractToFileAsync(fullPath, overwrite: true, cancellationToken).ConfigureAwait(false);\n\n                    // Preserve Unix file permissions from tar entry\n                    if (!environment.IsWindows() && entry.Mode != default)","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Cli/Utils/ArchiveHelper.cs#L74-L110","documentation":"ExtractTarGzSafe validates each tar entry's resolved path against the normalized destination directory and throws InvalidOperationException if the entry would extract outside it. This guards against tar-slip path traversal via '..' segments or absolute entry names.","triggerScenarios":"Extracting a tar.gz containing entries whose Name resolves outside the destination after GetFullPath(Path.Combine(destination, entry.Name)).","commonSituations":"Untrusted or tampered archives; archives built on systems that stored absolute paths in entry names; corrupted downloads.","solutions":["Download the archive from the official/trusted source and verify integrity.","List entry names (tar -tzf) to find offending entries and repack with relative paths.","Fix your packaging script if it created entries with absolute or '..' names."],"exampleFix":"// before\n// tar entry: \"/etc/evil\" (absolute path entry)\n// after\n// repack with relative entries: \"bin/evil\" -> correct relative path","handlingStrategy":"try-catch","validationCode":"await using var stream = File.OpenRead(tarGzPath);\nawait using var gz = new GZipStream(stream, CompressionMode.Decompress);\nusing var tar = new TarReader(gz);\nvar destFull = Path.GetFullPath(destinationPath);\nwhile (await tar.GetNextEntryAsync() is { } entry)\n{\n    var p = Path.GetFullPath(Path.Combine(destFull, entry.Name));\n    if (!p.StartsWith(destFull + Path.DirectorySeparatorChar, StringComparison.Ordinal)) throw new InvalidOperationException($\"Unsafe entry: {entry.Name}\");\n}","typeGuard":null,"tryCatchPattern":"try { await ArchiveHelper.ExtractAsync(tgzPath, dest, env, ct); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"Tar entry\")) { // reject untrusted archive\n}","preventionTips":["Verify archive checksums/signatures from trusted sources before extraction.","Pre-scan tar entries for '..' segments and absolute names.","Extract into an isolated temp directory."],"tags":["cli","tar","security","path-traversal"],"backgroundTag":"path-traversal-blocked","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-21T09:17:21.228Z"}