GHSA-h39g-6x3c-7fq9 Zio has SubFileSystem Path Confinement Bypass via Unresolved `..` Segment

Not scored Published

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.

PackageAffectedFixed in
Zio NuGetAll versions0.22.2
Zio NuGetAll versions0.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.

Sources

Is GHSA-h39g-6x3c-7fq9 in your software?

Upload an SBOM and sbomify checks it against every vulnerability here, every day.

Check your SBOMs for free