GitHub Security Advisory: GHSA-6c8g-7p36-r338
Package: SharpCompress (NUGET)
Severity: MODERATE (CVSS 5.9)
CWE: CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
Vulnerable versions: <= 0.47.4
Patched in: unpatched

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

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`):

```csharp
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`:

```csharp
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 entry** — `link` → `../evil_outside/`
   The `SymbolicLinkHandler` creates `/safe/extract/link` pointing outside the extraction root.

2. **File entry** — `link/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 supp