All rules
CA5389Security Enabled by default: No
Do not add archive item's path to the target file system path
Do not add archive item's path to the target file system path
Microsoft docsDescription
File path can be relative and can lead to file system access outside of the expected file system target path, leading to malicious config changes and remote code execution via lay-and-wait technique.
Cause
A non-sanitized source file path is used as the target file path in one of these parameters:
- parameter
destinationFileNameof method System.IO.Compression.ZipFileExtensions.ExtractToFile - parameter
pathof method System.IO.File.Open - parameter
pathof method System.IO.File.OpenWrite - parameter
pathof method System.IO.File.Create - parameter
pathof constructor for System.IO.FileStream - parameter
fileNameof constructor for System.IO.FileInfo
By default, this rule analyzes the entire codebase, but this is configurable.
How to fix violations
Do not use the source file path to construct the target file path, or make sure that the last character on the extraction path is the directory separator character.
Example
using System.IO.Compression;
class TestClass
{
public void TestMethod(ZipArchiveEntry zipArchiveEntry)
{
zipArchiveEntry.ExtractToFile(zipArchiveEntry.FullName);
}
}
using System;
using System.IO;
using System.IO.Compression;
class Program
{
static void Main(string[] args)
{
string zipPath = @".\result.zip";
Console.WriteLine("Provide path where to extract the zip file:");
string extractPath = Console.ReadLine();
// Normalizes the path.
extractPath = Path.GetFullPath(extractPath);
// Ensures that the last character on the extraction path
// is the directory separator char.
// Without this, a malicious zip file could try to traverse outside of the expected
// extraction path.
if (!extractPath.EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal))
extractPath += Path.DirectorySeparatorChar;
using (ZipArchive archive = ZipFile.OpenRead(zipPath))
{
foreach (ZipArchiveEntry entry in archive.Entries)
{
if (entry.FullName.EndsWith(".txt", StringComparison.OrdinalIgnoreCase))
{
// Gets the full path to ensure that relative segments are removed.
string destinationPath = Path.GetFullPath(Path.Combine(extractPath, entry.FullName));
// Ordinal match is safest, case-sensitive volumes can be mounted within volumes that
// are case-insensitive.
if (destinationPath.StartsWith(extractPath, StringComparison.Ordinal))
entry.ExtractToFile(destinationPath);
}
}
}
}
}When to suppress
You can suppress this warning if the source path always comes from a trusted source.
Your vote
Group results
0 yes 0 no
ConsensusNone (disabled)
Severity preference (yes voters)
Suggestion0
Warning0
Error0