Skip to content

Update dependency SharpCompress to 0.48.0 [SECURITY]#17

Open
renovate[bot] wants to merge 1 commit into
mainfrom
renovate/nuget-sharpcompress-vulnerability
Open

Update dependency SharpCompress to 0.48.0 [SECURITY]#17
renovate[bot] wants to merge 1 commit into
mainfrom
renovate/nuget-sharpcompress-vulnerability

Conversation

@renovate

@renovate renovate Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

ℹ️ Note

This PR body was truncated due to platform limits.

This PR contains the following updates:

Package Change Age Confidence
SharpCompress 0.39.00.48.0 age confidence

SharpCompress has directory traversal via directory entries in WriteToDirectory (zip slip variant)

CVE-2026-44788 / GHSA-6c8g-7p36-r338

More information

Details

Summary

A path traversal vulnerability in IArchive.WriteToDirectory() allows a malicious archive to create directories outside the intended extraction root. For TAR archives, this can be escalated to arbitrary file writes by chaining with a symlink entry, giving a full write primitive on the target filesystem subject to the permissions of the running process.

Details

The vulnerable code is in the directory-entry branch of WriteToDirectoryInternal (sync, IArchiveExtensions.cs:48–61) and WriteToDirectoryAsyncInternal (async, IAsyncArchiveExtensions.cs:70–84):

var dirPath = Path.Combine(destinationDirectory, entry.Key);
Directory.CreateDirectory(Path.GetDirectoryName(dirPath + "/"));

No Path.GetFullPath() normalisation and no bounds check are applied before the Directory.CreateDirectory call. Two .NET Path.Combine behaviours make this exploitable:

  • Relative traversal: Path.Combine("/safe/extract", "../../evil") → the OS resolves .. segments on the raw path, placing the directory outside the extraction root.
  • Absolute path override: Path.Combine("/safe/extract", "/tmp/evil") → returns "/tmp/evil" — the base is discarded entirely for rooted paths.

File entries are not directly affected — they route through ExtractionMethods.WriteEntryToDirectory which applies the correct guard (GetFullPath + StartsWith, see ExtractionMethods.cs:54–65). The directory-entry branch is a separate fast-path that was added without that guard.

Affected archive formats: ZIP and TAR (non-solid). Solid archives and 7-Zip use the reader path which calls the secure method.

Escalation to arbitrary file writes (TAR only)

Path.GetFullPath on .NET does not resolve symlinks — it only normalises . and .. segments. This means the file-entry guard in ExtractionMethods.WriteEntryToDirectory can be bypassed via symlink chaining in TAR archives when the caller supplies a SymbolicLinkHandler:

archive.WriteToDirectory("/safe/extract", new ExtractionOptions
{
    ExtractFullPath = true,
    SymbolicLinkHandler = (linkPath, linkTarget) =>
        File.CreateSymbolicLink(linkPath, linkTarget)  // naive — no validation of linkTarget
});

Attack sequence in a single TAR archive:

  1. Symlink entrylink../evil_outside/
    The SymbolicLinkHandler creates /safe/extract/link pointing outside the extraction root.

  2. File entrylink/secret.txt
    ExtractionMethods.WriteEntryToDirectory computes:

    • destdir = Path.GetFullPath("/safe/extract/link")"/safe/extract/link" — textually inside root, check passes ✓
    • File.Open("/safe/extract/link/secret.txt") — OS follows symlink, file is written to /evil_outside/secret.txt

The library does not validate linkTarget before passing it to the caller's handler, and the XML docs do not warn that it may be a traversal path. The idiomatic handler implementation above is therefore silently exploitable.

ZIP does not support symlinks in SharpCompress (ZipEntry.LinkTarget always returns null), so this escalation is TAR-only.

Attack ZIP TAR
Directory traversal (escape extraction root) Yes Yes
Escalate to arbitrary file writes via symlink chain No Yes (if caller provides SymbolicLinkHandler)

Recommended fix — apply the same pattern from ExtractionMethods.WriteEntryToDirectory to both affected files:

var fullDestDir = Path.GetFullPath(destinationDirectory);
if (!fullDestDir.EndsWith(Path.DirectorySeparatorChar))
    fullDestDir += Path.DirectorySeparatorChar;

var dirPath = Path.GetFullPath(Path.Combine(fullDestDir, entry.Key));
if (!dirPath.StartsWith(fullDestDir, PathComparison))
    throw new ExtractionException(
        "Entry is trying to create a directory outside of the destination directory.");

Directory.CreateDirectory(dirPath);

Additionally, the library should validate LinkTarget before invoking the caller's SymbolicLinkHandler, or document clearly that callers must validate it themselves.

PoC

A self-contained .NET console app is available at:
https://github.com/svenclaesson/poc-sharpcompress-traversal

git clone https://github.com/svenclaesson/poc-sharpcompress-traversal
cd poc-sharpcompress-traversal
dotnet run

The PoC crafts a ZIP with three directory entries (../../escaped_relative/, /tmp/escaped_absolute/, safe_subdir/) using System.IO.Compression (stdlib), then extracts with SharpCompress. Output shows [ESCAPED] for the two malicious entries and [ok] for the legitimate one, on both sync and async APIs.

Tested against SharpCompress 0.47.4 (latest NuGet).

Impact

This is a path traversal / zip slip vulnerability (CWE-22). Any application that calls archive.WriteToDirectory() on an untrusted archive is affected — which covers the primary documented extraction API.

For ZIP archives the impact is limited to arbitrary directory creation, which can be used to stage privilege escalation (e.g. cron drop-ins, XDG config paths, service spool directories) or shadow expected paths to alter application behaviour.

For TAR archives, callers that implement a SymbolicLinkHandler — which is the only way to faithfully restore a TAR — are exposed to a full arbitrary file write primitive via the symlink chaining described above.

Severity

  • CVSS Score: 5.9 / 10 (Medium)
  • Vector String: CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:H/A:L

References

This data is provided by the GitHub Advisory Database (CC-BY 4.0).


Release Notes

adamhathcock/sharpcompress (SharpCompress)

v0.48.0: - More fixes

Compare Source

Getting some fixes out to prep for bigger release - async writing might still not work on non-async streams

What's Changed

Full Changelog: adamhathcock/sharpcompress@0.47.4...0.48.0

v0.47.4: Buffer fixes!

Compare Source

What's Changed

Full Changelog: adamhathcock/sharpcompress@0.47.3...0.47.4

v0.47.3: - more checks

Compare Source

What's Changed

  • Fix denial-of-service crashes in 8 decompressors on malformed input by @​Copilot in #​1260

Full Changelog: adamhathcock/sharpcompress@0.47.2...0.47.3

v0.47.2: - ZStandard needs a bigger default buffer size

Compare Source

Making the default experience better with a larger buffer size.

What's Changed

  • Increase default RewindableBufferSize to 160KB to handle ZStandard tar detection by @​Copilot in #​1257

Full Changelog: adamhathcock/sharpcompress@0.47.1...0.47.2

v0.47.1: - Fix ZIP64 stream bounding and WinZip AES read-state corruption in ZIP reader

Compare Source

What's Changed

Full Changelog: adamhathcock/sharpcompress@0.47.0...0.47.1

v0.47.0: - The Release candidate for 1.0

Compare Source

I think this is the last breaking change before I mark things as 1.0. Looking for feedback

What's Changed

New Contributors

Full Changelog: adamhathcock/sharpcompress@0.46.4...0.47.0

v0.46.4: - zero length LZMA in Zip fix

Compare Source

What's Changed

Full Changelog: adamhathcock/sharpcompress@0.46.3...0.46.4

v0.46.3: - expose SharpCompressStream

Compare Source

What's Changed

Full Changelog: adamhathcock/sharpcompress@0.46.2...0.46.3

v0.46.2: - trying to get dependencies right for legacy frameworks

Compare Source

What's Changed

Full Changelog: adamhathcock/sharpcompress@0.46.1...0.46.2

v0.46.1: - quick fix for null 7z streams

Compare Source

What's Changed

  • Fix NullReferenceException when extracting 7z empty-stream entries by @​Copilot in #​1219

Full Changelog: adamhathcock/sharpcompress@0.46.0...0.46.1

v0.46.0: Async fixes that break the API

Compare Source

Open/Create must be asynchronous now so they return ValueTasks when they didn't before.

What's Changed

Full Changelog: adamhathcock/sharpcompress@0.45.1...0.46.0

v0.45.1: Fix for 7z and async

Compare Source

The big regression was fixed in 0.44.5 and 0.45.0 but only for sync. This does it for async too.

What's Changed

Full Changelog: adamhathcock/sharpcompress@0.45.0...0.45.1

v0.45.0: The big Async and API release

Compare Source

This release should be fully async as well as sync depending on the API used. I've endeavoured to make sure no sync methods are used when going via the async interface (and vice versa) but you never know.

Tests should cover things as well as the recent fixes (like the 7z regression)

Options and the API have been revamped so expect API breakages. I think it should be straight-forward but things won't compile.

There is a thing about Dispose vs async Disposing that may or may not be fully covered 😬

Feedback is welcome as I think 1.0 is around the corner with the introduction of Providers and other things. I wanted to get the async revamp out generally first though.

What's Changed

Full Changelog: adamhathcock/sharpcompress@0.44.5...0.45.0

v0.44.5: - 7z SOLID reading fix and buffer size consolidation

Compare Source

What's Changed

Full Changelog: adamhathcock/sharpcompress@0.44.4...0.44.5

v0.44.4: - 7z/LZMA perf fix

Compare Source

What's Changed

Full Changelog: adamhathcock/sharpcompress@0.44.3...0.44.4

v0.44.3: -real fix for 0.44.2

Compare Source

What's Changed

Full Changelog: adamhathcock/sharpcompress@0.44.2...0.44.3

v0.44.2: - making EntryStream Dispose more tolerant

Compare Source

What's Changed

Full Changelog: adamhathcock/sharpcompress@0.44.1...0.44.2

v0.44.1: - add new leave open on streams that changed

Compare Source

What's Changed

Full Changelog: adamhathcock/sharpcompress@0.44.0...0.44.1

v0.44.0: - fast follow with critical fixes, new features and dependency bumps

Compare Source

What's Changed

Full Changelog: adamhathcock/sharpcompress@0.43.0...0.44.0

v0.43.0: - more fixes, more async, more AI

Compare Source

Big changes:
Progress was redone to use IProgress.
ZstdSharp was moved into the project.
More groundwork for full async as well as more contributions and bug fixes!

What's Changed

New Contributors

Full Changelog: adamhathcock/sharpcompress@0.42.0...0.43.0

v0.42.1: - ARJ fix

Compare Source

What's Changed

Full Changelog: adamhathcock/sharpcompress@0.42.0...0.42.1

v0.42.0: - Async, ARJ and AI

Compare Source

This is one where I leaned heavily on AI for asynchronous implementation and bug fixes. ARJ is provided by @​TwanVanDongen

What's Changed

New Contributors

Full Changelog: adamhathcock/sharpcompress@0.41.0...0.42.0

v0.41.0: - bigger changes for streams

Compare Source

What's Changed

New Contributors

Full Changelog: adamhathcock/sharpcompress@0.40.0...0.41.0

v0.40.0: - fixes galore!

Compare Source

What's Changed

Note

PR body was truncated to here.


Configuration

📅 Schedule: (UTC)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants