Your RSA-2048 keys break in 2030. Find every one of them before attackers do.
.NET
.NET NuGet
Not in CISA KEV
LOW severity

GHSA-h39g-6x3c-7fq9 Zio

LOWFix: xoofx/zio@c8c2f53

GHSA-h39g-6x3c-7fq9 is a low-severity (CVSS 3.8) vulnerability in Zio. A fix is available for Zio — see the affected versions and patch details below.

Zio has SubFileSystem Path Confinement Bypass via Unresolved `..` Segment

Published
Apr 18, 2026
Updated
Apr 18, 2026
Affected
1 pkg
Patched
1 / 1
Exploits
None indexed
Exploitation data as of Apr 18, 2026 · OSV.dev, FIRST.org (EPSS)

Real-World Exposure

1 pkg affected
.NETZio

Real-time download stats are indexed for npm and PyPI packages. This vulnerability affects NuGet packages — download data is not available via public APIs for these ecosystems.

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.

Affected Packages

1 total 1 fixed
EcosystemPackageVulnerable rangeFix
.NETNuGetZioall versions0.22.2dotnet add package Zio --version 0.22.2

Detection & mitigation playbook

Open-source dependency
  1. Detect

    Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for Zio, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.

  2. Fix

    Update Zio to 0.22.2 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms GHSA-h39g-6x3c-7fq9 is resolved across your whole dependency graph.

  3. Workarounds

    If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.

  4. How O3 protects you

    O3 Security's impact-aware SCA analyses which vulnerable code paths your application actually calls, so a match like GHSA-h39g-6x3c-7fq9 can be triaged on real exposure rather than presence alone.

Tailored to GHSA-h39g-6x3c-7fq9. Runtime protection reduces exposure until a permanent patch is applied and verified — it complements patching, it doesn't replace it.

Frequently Asked Questions

# 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. ```csharp if (!processParts && i + 1 == path.Length) return path.Substring(0, path.Length - 1); ``` When the input ends with `/` or `\`, and `proce
O3 Security · Impact-Aware SCA

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

O3 Security finds GHSA-h39g-6x3c-7fq9 across NuGet dependencies, including transitive ones, and its impact-aware SCA ranks findings by whether your code actually calls the vulnerable path.

GHSA-h39g-6x3c-7fq9: Zio (Low 3.8) | O3 Security