GHSA-74p7-6h78-gw8p: skillctl Denial of Service Vulnerability

HIGH
Advisory Summary

GHSA-74p7-6h78-gw8p is a HIGH denial of service vulnerability (CWE-400: Uncontrolled Resource Consumption) affecting skillctl libraries in the crates.io ecosystem. The issue involves argument injection, path traversal in --dest, fifo/device dos, hardlink exfiltration, and commit-trailer forgery. Remediation is available by upgrading affected packages to version 0.1.3.

GHSA-74p7-6h78-gw8p at a Glance

CVE Identifier N/A
GHSA Identifier GHSA-74p7-6h78-gw8p
Severity HIGH
CVSS v3.1 Base Score N/A
CWE Classification CWE-400: Uncontrolled Resource Consumption
Affected Product skillctl
Package Ecosystem crates.io
Published Date
Last Updated

How to Fix GHSA-74p7-6h78-gw8p

To remediate this vulnerability, upgrade all affected skillctl dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

skillctl fixed: 0.1.3
Upgrade skillctl to 0.1.3
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

inspect dependencies for skillctl

How to Check if You Are Affected

To determine whether your application is affected by GHSA-74p7-6h78-gw8p, inspect your project dependencies for skillctl:

inspect dependencies for skillctl

Analyze the terminal output to locate any version of skillctl in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 0.1.3), your application is affected.

Note: Verify declared build manifests and deployed runtime container environments.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-400: Uncontrolled Resource Consumption, where the product does not properly control the allocation and maintenance of a limited resource. In skillctl, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

## Impact Following the path-safety patches in [GHSA-wx3m-whqv-xv47](https://github.com/umanio-agency/skillctl/security/advisories/GHSA-wx3m-whqv-xv47) (v0.1.2), a comprehensive multi-angle audit surfaced five further vulnerabilities, now patched in v0.1.3: 1. **`source_sha` argument injection in `git ls-tree` (CRITICAL).** `InstalledSkill.source_sha` deserialized from `.skills.toml` (committed, PR-mergeable) flowed unvalidated into `git ls-tree -r -z <refspec> -- <path>`. Because the refspec sits before `--`, an attacker who slipped a malicious `.skills.toml` into a PR could set `source_sha = "--name-only"` / `--abbrev=0` / `--output=…` and corrupt the diff classifier (which drives `pull` / `push` destructive decisions), or forge a divergence state to trick `push --on-divergence overwrite` into clobbering the wrong content. 2. **FIFO / device / socket denial-of-service in `copy_dir_all` (CRITICAL).** The file-type branch only checked `is_dir()` / `is_symlink()`; a FIFO inside a skill folder fell through to `fs::copy`, which blocks indefinitely waiting for a writer. A character device like `/dev/zero` would read until OOM. Reachable on `skillctl add` against any adversarial library. 3. **`add --dest` arbitrary-directory wipe in agent mode (HIGH).** `--dest` accepted absolute paths and `..` traversal without validation, so a single invocation `skillctl add --dest /Users/victim/.ssh --on-conflict overwrite --skill <maliciously-named>` would `remove_dir_all` arbitrary directories — no `.skills.toml` round-trip required. Reachable in any non-interactive / agent-driven workflow where flag values may be attacker-supplied. 4. **Commit-message trailer forgery via skill names (HIGH).** Skill names were spliced verbatim into `git commit -m "update skill: <name>"` and into the `commit.message` field of `--json` output. A skill named `foo\nCo-Authored-By: evil@x` produced a forged commit trailer that downstream tooling (Linear, GitHub commit-bot, release-notes scrapers) treats as real authorship metadata. 5. **Hardlink exfiltration via the round-trip (HIGH).** `fs::symlink_metadata` reports a regular file for hardlinks (shared inode), and `fs::copy` reads the target content. An untrusted agent writing `<project>/my-skill/data` as a hardlink to `~/.ssh/id_rsa` would have shipped the SSH key content to the (possibly public) library on the next `skillctl push` or `detect`. ## Patches Fixed in [v0.1.3](https://github.com/umanio-agency/skillctl/releases/tag/v0.1.3): - `InstalledSkill::validate` rejects any `source_sha` that isn't 40–64 hex characters. - `fs_util::copy_dir_all` only allows regular files and directories; FIFO / socket / device / other special files are rejected with `AppError::Config`. - `commands::add::resolve_destination` rejects `..` unconditionally and rejects absolute paths in non-interactive / `--json` mode. - New `src/sanitize.rs` module: `validate_identifier` (strict, no control bytes / newlines / ESC, used for skill `name` + individual `tags`) and `validate_message_safe` (lenient, allows `\n` + `\t`, rejects `\r` + DEL + C0/C1 controls, used for `description` and `--message`). Wired at the `skill::discover` and `read_tags` boundaries so poisoned skills are dropped silently and poisoned descriptions/tags are stripped from otherwise-valid skills. - `fs_util::copy_dir_all` checks `metadata.nlink() > 1` on regular files (Unix) and refuses hardlinked content. All checks are lexical or single-syscall (`symlink_metadata`, `metadata`). No `canonicalize`, no TOCTOU windows. 23 new unit + integration tests cover each rejection class; `cargo test`: 95 pass; clippy clean; `cargo audit` clean. ## Workarounds Upgrade to v0.1.3. Pre-patch mitigations are awkward but possible: - Audit every `.skills.toml` `source_sha` field before running `skillctl pull` / `push` / `detect`. - Audit library content for FIFO / device files and hardlinks before running `skillctl add`. - Never invoke `skillctl add` with attacker-controllable `--dest` values in agent / CI contexts. - Never use `--message` with attacker-controlled content. ## Credit The findings were surfaced by a maintainer-led multi-angle audit (6 parallel sub-agents, one per threat-model dimension) following the firebaguette audit that motivated v0.1.2. The methodology (cross-agent convergence to identify the most exploitable items) is documented in the project's internal decisions log; the strongest signal was the four-of-six independent convergence on the `source_sha` vector. ## Resources - Fix commit: [28dfce3](https://github.com/umanio-agency/skillctl/commit/28dfce3) - Release: https://github.com/umanio-agency/skillctl/releases/tag/v0.1.3 - Prior advisory (path-safety + symlinks): [GHSA-wx3m-whqv-xv47](https://github.com/umanio-agency/skillctl/security/advisories/GHSA-wx3m-whqv-xv47)

GHSA-74p7-6h78-gw8p Affected skillctl Versions

1 component(s)
Fixed Versions:
0.1.3
Product / Package Ecosystem Affected Versions Fixed Version
skillctl
crates.io
< 0.1.3
0.1.3

References

Frequently Asked Questions

What is GHSA-74p7-6h78-gw8p?
GHSA-74p7-6h78-gw8p is a security vulnerability in skillctl involving argument injection, path traversal in --dest, FIFO/device DoS, hardlink exfiltration, and commit-trailer forgery under CWE-400: Uncontrolled Resource Consumption.
Which skillctl versions are affected?
Affected versions include releases prior to 0.1.3 across affected packages: skillctl.
What version fixes GHSA-74p7-6h78-gw8p?
Upgrading to 0.1.3 (or the latest patched release for your respective branch) resolves the vulnerability.
Is skillctl affected?
Yes, skillctl is affected in releases prior to 0.1.3. Upgrade your dependency to 0.1.3 or later.
What CWE is associated with GHSA-74p7-6h78-gw8p?
GHSA-74p7-6h78-gw8p is classified under CWE-400: Uncontrolled Resource Consumption (The product does not properly control the allocation and maintenance of a limited resource.).
How can I check crates.io dependencies for GHSA-74p7-6h78-gw8p?
Run the dependency tree command: 'inspect dependencies for skillctl'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-74p7-6h78-gw8p",
  "modified" : "2026-06-22T22:45:16Z",
  "published" : "2026-06-22T22:45:16Z",
  "aliases" : [ ],
  "summary" : "skillctl: argument injection, path traversal in --dest, FIFO/device DoS, hardlink exfiltration, and commit-trailer forgery",
  "details" : "## Impact\n\nFollowing the path-safety patches in [GHSA-wx3m-whqv-xv47](https://github.com/umanio-agency/skillctl/security/advisories/GHSA-wx3m-whqv-xv47) (v0.1.2), a comprehensive multi-angle audit surfaced five further vulnerabilities, now patched in v0.1.3:\n\n1. **`source_sha` argument injection in `git ls-tree` (CRITICAL).** `InstalledSkill.source_sha` deserialized from `.skills.toml` (committed, PR-mergeable) flowed unvalidated into `git ls-tree -r -z <refspec> -- <path>`. Because the refspec sits before `--`, an attacker who slipped a malicious `.skills.toml` into a PR could set `source_sha = \"--name-only\"` / `--abbrev=0` / `--output=…` and corrupt the diff classifier (which drives `pull` / `push` destructive decisions), or forge a divergence state to trick `push --on-divergence overwrite` into clobbering the wrong content.\n2. **FIFO / device / socket denial-of-service in `copy_dir_all` (CRITICAL).** The file-type branch only checked `is_dir()` / `is_symlink()`; a FIFO inside a skill folder fell through to `fs::copy`, which blocks indefinitely waiting for a writer. A character device like `/dev/zero` would read until OOM. Reachable on `skillctl add` against any adversarial library.\n3. **`add --dest` arbitrary-directory wipe in agent mode (HIGH).** `--dest` accepted absolute paths and `..` traversal without validation, so a single invocation `skillctl add --dest /Users/victim/.ssh --on-conflict overwrite --skill <maliciously-named>` would `remove_dir_all` arbitrary directories — no `.skills.toml` round-trip required. Reachable in any non-interactive / agent-driven workflow where flag values may be attacker-supplied.\n4. **Commit-message trailer forgery via skill names (HIGH).** Skill names were spliced verbatim into `git commit -m \"update skill: <name>\"` and into the `commit.message` field of `--json` output. A skill named `foo\\nCo-Authored-By: evil@x` produced a forged commit trailer that downstream tooling (Linear, GitHub commit-bot, release-notes scrapers) treats as real authorship metadata.\n5. **Hardlink exfiltration via the round-trip (HIGH).** `fs::symlink_metadata` reports a regular file for hardlinks (shared inode), and `fs::copy` reads the target content. An untrusted agent writing `<project>/my-skill/data` as a hardlink to `~/.ssh/id_rsa` would have shipped the SSH key content to the (possibly public) library on the next `skillctl push` or `detect`.\n\n## Patches\n\nFixed in [v0.1.3](https://github.com/umanio-agency/skillctl/releases/tag/v0.1.3):\n\n- `InstalledSkill::validate` rejects any `source_sha` that isn't 40–64 hex characters.\n- `fs_util::copy_dir_all` only allows regular files and directories; FIFO / socket / device / other special files are rejected with `AppError::Config`.\n- `commands::add::resolve_destination` rejects `..` unconditionally and rejects absolute paths in non-interactive / `--json` mode.\n- New `src/sanitize.rs` module: `validate_identifier` (strict, no control bytes / newlines / ESC, used for skill `name` + individual `tags`) and `validate_message_safe` (lenient, allows `\\n` + `\\t`, rejects `\\r` + DEL + C0/C1 controls, used for `description` and `--message`). Wired at the `skill::discover` and `read_tags` boundaries so poisoned skills are dropped silently and poisoned descriptions/tags are stripped from otherwise-valid skills.\n- `fs_util::copy_dir_all` checks `metadata.nlink() > 1` on regular files (Unix) and refuses hardlinked content.\n\nAll checks are lexical or single-syscall (`symlink_metadata`, `metadata`). No `canonicalize`, no TOCTOU windows. 23 new unit + integration tests cover each rejection class; `cargo test`: 95 pass; clippy clean; `cargo audit` clean.\n\n## Workarounds\n\nUpgrade to v0.1.3. Pre-patch mitigations are awkward but possible:\n- Audit every `.skills.toml` `source_sha` field before running `skillctl pull` / `push` / `detect`.\n- Audit library content for FIFO / device files and hardlinks before running `skillctl add`.\n- Never invoke `skillctl add` with attacker-controllable `--dest` values in agent / CI contexts.\n- Never use `--message` with attacker-controlled content.\n\n## Credit\n\nThe findings were surfaced by a maintainer-led multi-angle audit (6 parallel sub-agents, one per threat-model dimension) following the firebaguette audit that motivated v0.1.2. The methodology (cross-agent convergence to identify the most exploitable items) is documented in the project's internal decisions log; the strongest signal was the four-of-six independent convergence on the `source_sha` vector.\n\n## Resources\n\n- Fix commit: [28dfce3](https://github.com/umanio-agency/skillctl/commit/28dfce3)\n- Release: https://github.com/umanio-agency/skillctl/releases/tag/v0.1.3\n- Prior advisory (path-safety + symlinks): [GHSA-wx3m-whqv-xv47](https://github.com/umanio-agency/skillctl/security/advisories/GHSA-wx3m-whqv-xv47)",
  "severity" : [ ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "crates.io",
      "name" : "skillctl"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "0.1.3"
      } ]
    } ]
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/umanio-agency/skillctl/security/advisories/GHSA-74p7-6h78-gw8p"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/umanio-agency/skillctl/security/advisories/GHSA-wx3m-whqv-xv47"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/umanio-agency/skillctl/commit/28dfce3"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/umanio-agency/skillctl"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/umanio-agency/skillctl/releases/tag/v0.1.3"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-22", "CWE-400", "CWE-59", "CWE-88", "CWE-93" ],
    "severity" : "HIGH",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-06-22T22:45:16Z",
    "nvd_published_at" : null
  }
}