{"answers":{"affected":"2 open source packages ship an affected version, including Zio.","exploited":"There is no known exploitation of GHSA-h39g-6x3c-7fq9 in the wild and no public exploit code.","fix":"Upgrade Zio to 0.22.2 or later.","what":"GHSA-h39g-6x3c-7fq9 is a path traversal vulnerability in Zio, published on 18 Apr 2026."},"fix_prompt":"Check this codebase for GHSA-h39g-6x3c-7fq9 and fix it if it is affected.\n\nWhat it is: GHSA-h39g-6x3c-7fq9 is a path traversal vulnerability in Zio, published on 18 Apr 2026. \nExploitation: There is no known exploitation of GHSA-h39g-6x3c-7fq9 in the wild and no public exploit code.\n\nAffected packages and fixed versions:\n- Zio (NuGet): affected all versions; fixed in 0.22.2\n- Zio (NuGet): affected all versions; fixed in 0.22.2\n\nTask:\n1. Search the dependency manifests and lockfiles (for example package.json, package-lock.json, requirements.txt, poetry.lock, uv.lock, pom.xml, build.gradle, go.mod, Cargo.lock, Gemfile.lock) and any Dockerfiles for the affected packages, including transitive dependencies.\n2. If an affected version is in use, upgrade it to the fixed version for its release line with the project's package manager, so the lockfile is regenerated. Prefer the smallest upgrade that fixes it.\n3. If there is no fix, or the upgrade would break the build, do not guess: explain the risk and the safest workaround instead.\n4. Run the tests and summarise what changed and why.\n5. If nothing in the project is affected, say so and change nothing.\n\nReference: https://insights.sbomify.com/GHSA-h39g-6x3c-7fq9/ (Markdown: https://insights.sbomify.com/GHSA-h39g-6x3c-7fq9/index.md)","id":"GHSA-h39g-6x3c-7fq9","markdown":"https://insights.sbomify.com/GHSA-h39g-6x3c-7fq9/index.md","name":"GHSA-h39g-6x3c-7fq9","record":{"aliases":[],"analysis":{"component_type":"library","fix_type":"upgrade","impacts":["data_read","data_modify"],"network_reachable":"unknown","non_default_config":false,"product_category":"Zio file system library","requires_auth":"none","summary":"Attackers can bypass SubFileSystem path confinement using unresolved '..' segments to access parent directories, potentially reading or modifying files outside the intended sandbox.","user_interaction":"not_required","vuln_class":"path_traversal"},"analysis_generated_by":"qwen3.8-flash-next","assigner":null,"cpe":[],"cvss":{"score":null,"severity":null,"source":null,"vector":null,"version":null},"cwes":[],"description":"# Summary\n\n`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.\n\n# Affected Component\n\n`Zio.UPath.ValidateAndNormalize`\n`Zio.FileSystems.SubFileSystem`\n\n`UPath.ValidateAndNormalize` has a trailing slash optimisation.\n\n```csharp\nif (!processParts \u0026\u0026 i + 1 == path.Length)\n    return path.Substring(0, path.Length - 1);\n```\n\nWhen 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.\n\nThe resulting `UPath` with `FullName = \"/..\"` is absolute, contains no control characters, and no colon so it passes `FileSystem.ValidatePath` without rejection.\n\nWhen this path reaches `SubFileSystem.ConvertPathToDelegate`:\n\n```csharp\nprotected override UPath ConvertPathToDelegate(UPath path)\n{\n    var safePath = path.ToRelative();     // \"/..\".ToRelative() = \"..\"\n    return SubPath / safePath;            // \"/jail\" / \"..\" = \"/\"  (resolved by Combine)\n}\n```\n\nThe delegate filesystem receives `/` (the root) instead of a path under `/jail`.\n\n# Proof of Concept\n\n```csharp\nusing Zio;\nusing Zio.FileSystems;\n\nvar root = new MemoryFileSystem();\nroot.CreateDirectory(\"/sandbox\");\nvar sub = new SubFileSystem(root, \"/sandbox\");\n\nConsole.WriteLine(sub.DirectoryExists(\"/../\"));           // True (sees parent root)\nConsole.WriteLine(sub.ConvertPathToInternal(\"/../\"));     // \"/\" (parent root path)\n```\n\n# Impact\n\nThe 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.","ecosystems":["NuGet"],"exploits":{"exploitdb":null,"first_seen":null,"github_poc":null,"max_poc_stars":null,"metasploit":null,"nuclei":null,"refs":[],"tier":null},"has_fix":true,"headline":"Zio has SubFileSystem Path Confinement Bypass via Unresolved `..` Segment","id":"GHSA-h39g-6x3c-7fq9","indexable":true,"kev":null,"kind":"advisory","links":{"ecosystem":"NuGet","product":null,"products":[],"type":"path_traversal","year":"2026"},"n_packages":2,"n_references":null,"packages":[{"ecosystem":"NuGet","fixed":["0.22.2"],"introduced":["0"],"last_affected":[],"package":"Zio","purl":null,"source":"GHSA-h39g-6x3c-7fq9"},{"ecosystem":"NuGet","fixed":["0.22.2"],"introduced":["0"],"last_affected":[],"package":"Zio","purl":"pkg:nuget/Zio","source":"GHSA-h39g-6x3c-7fq9"}],"products":null,"published":"2026-04-18","related":[],"sources":[{"class":"attribution","licence":"CC BY 4.0","name":"GitHub Advisory Database","prefix":"GHSA"}],"ssvc":{"automatable":null,"exploitation":null,"technical_impact":null},"state":null,"updated":null,"vendors":null},"summary":"Attackers can bypass SubFileSystem path confinement using unresolved '..' segments to access parent directories, potentially reading or modifying files outside the intended sandbox.","url":"https://insights.sbomify.com/GHSA-h39g-6x3c-7fq9/"}