GHSA-wx3m-whqv-xv47

Suggest an improvement
Source
https://github.com/advisories/GHSA-wx3m-whqv-xv47
Import Source
https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/06/GHSA-wx3m-whqv-xv47/GHSA-wx3m-whqv-xv47.json
JSON Data
https://api.osv.dev/v1/vulns/GHSA-wx3m-whqv-xv47
Published
2026-06-05T19:43:51Z
Modified
2026-06-19T05:15:08Z
Severity
  • 7.1 (High) CVSS_V4 - CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:H/VI:N/VA:L/SC:N/SI:N/SA:N CVSS Calculator
Summary
skillctl: Path traversal and symlink-follow in skillctl allow arbitrary file disclosure and deletion
Details

Impact

skillctl 0.1.0 and 0.1.1 contained four path-safety vulnerabilities that, in combination, allowed an attacker to:

  1. Exfiltrate arbitrary files on the operator's machine by publishing a malicious skills library containing a symlink inside a skill folder (e.g. niania → /home/user/.aws/credentials). The symlink fell through entry.file_type().is_dir() in fs_util::copy_dir_all, was dereferenced by fs::copy, and the target's content was copied into the project. A subsequent skillctl push would have published the secret to the (possibly public) library — what the reporter called "round-trip path exfiltration".

  2. Delete arbitrary directories outside the project or library root by crafting a .skills.toml with a malicious destination or source_path field. Both were deserialized as PathBuf with zero validation. Because Path::join lets an absolute right-hand side replace the base, destination = "/home/user/.ssh" made cwd.join(...) resolve outside the project; .. traversal was equally unguarded. Downstream remove_dir_all in replace_folder_contents then wiped arbitrary writable directories on skillctl pull / push / detect. .skills.toml is the exact kind of file teams commit and exchange via PR; a single merged malicious PR was sufficient to weaponise the maintainer's next skillctl pull --all.

  3. detect --target accepted .. traversal, even though absolute paths were rejected. --target ../../../etc would have written outside the library root.

  4. Fork-name validation accepted . and .. literally, so a fork named .. would have produced a Path::join resolving to the parent directory and fs::rename could have clobbered it.

Patches

Fixed in v0.1.2:

  • Symlinks inside skill folders are hard-rejected at copy time (both top-level source and any descendant entry).
  • .skills.toml destination and source_path are validated at load time and reject absolute paths, .. components, and Windows-prefix components.
  • A new path_safety::safe_join helper is wired (defense-in-depth) at every destructive call site in pull.rs / push.rs.
  • detect --target and the interactive custom-path prompt go through the same validate_relative_subpath helper.
  • validate_fork_name explicitly rejects . and ...

Threat-model note: the fix is purely lexical (component-level) plus an explicit symlink check at copy time. No filesystem canonicalize calls were added, avoiding TOCTOU windows.

Credit

Reported privately on 2026-05-19 by firebaguette via the Umanio Discord (the reporter declined GitHub credit, so this advisory carries no structured credits field).

Database specific
{
    "cwe_ids":  [
        "CWE-22",
        "CWE-61"
    ],
    "github_reviewed":  true,
    "github_reviewed_at":  "2026-06-05T19:43:51Z",
    "nvd_published_at":  null,
    "severity":  "HIGH"
}
References

Affected packages

crates.io / skillctl

Package

Name
skillctl
View open source insights on deps.dev
Purl
pkg:cargo/skillctl

Affected ranges

Type
SEMVER
Events
Introduced
0 Unknown introduced version / All previous versions are affected
Fixed
0.1.2

Database specific

source
"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/06/GHSA-wx3m-whqv-xv47/GHSA-wx3m-whqv-xv47.json"