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 docs

Description

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 destinationFileName of method System.IO.Compression.ZipFileExtensions.ExtractToFile
  • parameter path of method System.IO.File.Open
  • parameter path of method System.IO.File.OpenWrite
  • parameter path of method System.IO.File.Create
  • parameter path of constructor for System.IO.FileStream
  • parameter fileName of 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.

Group results
0 yes 0 no
ConsensusNone (disabled)
Severity preference (yes voters)
Suggestion0
Warning0
Error0