GHSA-h39g-6x3c-7fq9 Zio has SubFileSystem Path Confinement Bypass via Unresolved `..` Segment
Attackers can bypass SubFileSystem path confinement using unresolved '..' segments to access parent directories, potentially reading or modifying files outside the intended sandbox.
- Exploited in the wild
- Not known
- Login needed
- Not needed
- Attackable
- Not stated
- Victim action needed
- Not needed
- Fix
- Available
What is GHSA-h39g-6x3c-7fq9?
GHSA-h39g-6x3c-7fq9 is a path traversal vulnerability in Zio, published on 18 Apr 2026.
Official description
Summary
SubFileSystem fails to confine operations to its declared sub path when the input path is /../ (or equivalents /../, /..\\). This path passes all validation but resolves to the root of the parent filesystem, allowing directory level operations outside the intended boundary.
Affected Component
Zio.UPath.ValidateAndNormalize
Zio.FileSystems.SubFileSystem
UPath.ValidateAndNormalize has a trailing slash optimisation.
if (!processParts && i + 1 == path.Length)
return path.Substring(0, path.Length - 1);
When the input ends with / or \, and processParts is still false, the function strips the trailing separator and returns immediately before the .. resolution logic runs. The input /../ triggers this path: the trailing / is the last character, processParts has not been set (because .. as the first relative segment after root is specifically exempted), so the function returns /.. with the .. segment unresolved.
The resulting UPath with FullName = "/.." is absolute, contains no control characters, and no colon so it passes FileSystem.ValidatePath without rejection.
When this path reaches SubFileSystem.ConvertPathToDelegate:
protected override UPath ConvertPathToDelegate(UPath path)
{
var safePath = path.ToRelative(); // "/..".ToRelative() = ".."
return SubPath / safePath; // "/jail" / ".." = "/" (resolved by Combine)
}
The delegate filesystem receives / (the root) instead of a path under /jail.
Proof of Concept
using Zio;
using Zio.FileSystems;
var root = new MemoryFileSystem();
root.CreateDirectory("/sandbox");
var sub = new SubFileSystem(root, "/sandbox");
Console.WriteLine(sub.DirectoryExists("/../")); // True (sees parent root)
Console.WriteLine(sub.ConvertPathToInternal("/../")); // "/" (parent root path)
Impact
The escape is limited to directory level operations because appending a filename after .. (e.g., /../file.txt) causes normal .. resolution to trigger, which correctly rejects the path as going above root. Only the bare terminal /../ (which strips to /..) survives. This means that exploitability is limited, and this vulnerability does not escalate to file read/write.
Which versions are affected by GHSA-h39g-6x3c-7fq9?
2 open source packages ship an affected version, including Zio.
| Package | Affected | Fixed in |
|---|---|---|
Zio NuGet | All versions | 0.22.2 |
Zio NuGet | All versions | 0.22.2 |
How do I fix GHSA-h39g-6x3c-7fq9?
Upgrade Zio to 0.22.2 or later.
Upgrade, and resolve every user-supplied path against an allowed base folder before opening it. More about Path traversal.
Is GHSA-h39g-6x3c-7fq9 being exploited?
There is no known exploitation of GHSA-h39g-6x3c-7fq9 in the wild and no public exploit code.