Read the docs
TI-2026-66825 Aliases GHSA-wx3m-whqv-xv47

skillctl: Path traversal and symlink-follow in skillctl allow arbitrary file disclosure and deletion

Priority LOW 38CWE-22Published · Updated

Key facts

Attack vector
—
Privileges required
—
User interaction
—
Attack complexity
—
Impact type
—
Confidentiality · integrity · availability
—
Fix status
Fixed

No CVSS vector from any source. Fix status from GitHub.

Summary

## 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](https://github.com/umanio-agency/skillctl/releases/tag/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).

Why it matters now

Fix Fixed skillctl (crates.io): 0.1.2

SSVC decision points

Not available: CISA has not published SSVC decision points for this record.

Affected products

VendorProductAffected versionsFixed inStatusSource
—skillctl (crates.io)before 0.1.20.1.2Patch availableGHSA-wx3m-whqv-xv47
  • skillctl (crates.io) Vendor— Affected before 0.1.2 Fixed in 0.1.2 Patch available GHSA-wx3m-whqv-xv47

Remediation

  • Fix · GHSA-wx3m-whqv-xv47 skillctl (crates.io) Fixed in 0.1.2 Advisory →

Timeline

  1. 2026-10-03 Threatist record created from GHSA-wx3m-whqv-xv47

References

Sources

This product uses the NVD API but is not endorsed or certified by the NVD. Sources and licences