diff --git a/test/ICSharpCode.SharpZipLib.Tests/ICSharpCode.SharpZipLib.Tests.csproj b/test/ICSharpCode.SharpZipLib.Tests/ICSharpCode.SharpZipLib.Tests.csproj
index fd6f61ae9..12183fcdd 100644
--- a/test/ICSharpCode.SharpZipLib.Tests/ICSharpCode.SharpZipLib.Tests.csproj
+++ b/test/ICSharpCode.SharpZipLib.Tests/ICSharpCode.SharpZipLib.Tests.csproj
@@ -5,6 +5,7 @@
netcoreapp3.1;net46
+ 8
diff --git a/test/ICSharpCode.SharpZipLib.Tests/Tar/TarArchiveTests.cs b/test/ICSharpCode.SharpZipLib.Tests/Tar/TarArchiveTests.cs
new file mode 100644
index 000000000..e7a2bcd7f
--- /dev/null
+++ b/test/ICSharpCode.SharpZipLib.Tests/Tar/TarArchiveTests.cs
@@ -0,0 +1,73 @@
+using System.IO;
+using System.Text;
+using ICSharpCode.SharpZipLib.Core;
+using ICSharpCode.SharpZipLib.Tar;
+using static ICSharpCode.SharpZipLib.Tests.TestSupport.Utils;
+using NUnit.Framework;
+
+namespace ICSharpCode.SharpZipLib.Tests.Tar
+{
+ [TestFixture]
+ public class TarArchiveTests
+ {
+ [Test]
+ [Category("Tar")]
+ [Category("CreatesTempFile")]
+ public void ExtractingContentsWithNonTraversalPathSucceeds()
+ {
+ Assert.DoesNotThrow(() => ExtractTarOK("output", "test-good", allowTraverse: false));
+ }
+
+ [Test]
+ [Category("Tar")]
+ [Category("CreatesTempFile")]
+ public void ExtractingContentsWithExplicitlyAllowedTraversalPathSucceeds()
+ {
+ Assert.DoesNotThrow(() => ExtractTarOK("output", "../file", allowTraverse: true));
+ }
+
+ [Test]
+ [Category("Tar")]
+ [Category("CreatesTempFile")]
+ [TestCase("output", "../file")]
+ [TestCase("output", "../output.txt")]
+ public void ExtractingContentsWithDisallowedPathsFails(string outputDir, string fileName)
+ {
+ Assert.Throws(() => ExtractTarOK(outputDir, fileName, allowTraverse: false));
+ }
+
+ public void ExtractTarOK(string outputDir, string fileName, bool allowTraverse)
+ {
+ var fileContent = Encoding.UTF8.GetBytes("file content");
+ using var tempDir = new TempDir();
+
+ var tempPath = tempDir.Fullpath;
+ var extractPath = Path.Combine(tempPath, outputDir);
+ var expectedOutputFile = Path.Combine(extractPath, fileName);
+
+ using var archiveStream = new MemoryStream();
+
+ Directory.CreateDirectory(extractPath);
+
+ using (var tos = new TarOutputStream(archiveStream, Encoding.UTF8){IsStreamOwner = false})
+ {
+ var entry = TarEntry.CreateTarEntry(fileName);
+ entry.Size = fileContent.Length;
+ tos.PutNextEntry(entry);
+ tos.Write(fileContent, 0, fileContent.Length);
+ tos.CloseEntry();
+ }
+
+ archiveStream.Position = 0;
+
+ using (var ta = TarArchive.CreateInputTarArchive(archiveStream, Encoding.UTF8))
+ {
+ ta.ProgressMessageEvent += (archive, entry, message)
+ => TestContext.WriteLine($"{entry.Name} {entry.Size} {message}");
+ ta.ExtractContents(extractPath, allowTraverse);
+ }
+
+ Assert.That(File.Exists(expectedOutputFile));
+ }
+ }
+}