Jun 5, 2026·6 min read·12 visits
A cluster of path-safety flaws in skillctl allows attackers to exfiltrate local files via symbolic links and delete arbitrary directories using manipulated path configurations.
An analysis of four critical vulnerabilities in the skillctl Rust crate (versions 0.1.0 and 0.1.1) that allow arbitrary file exfiltration and directory deletion.
The skillctl command-line utility is a Rust crate designed to manage and synchronize personal agent skill libraries across software engineering projects. In versions 0.1.0 and 0.1.1, the tool suffers from a critical cluster of filesystem path validation and symbolic link handling vulnerabilities. These flaws expose operators to potential arbitrary file disclosure and arbitrary directory deletion.
The primary attack surface resides within the mechanism used to clone, copy, and synchronize skill folders. This process involves copying directory structures from remote or local repositories and reading configuration definitions from user-supplied .skills.toml files. Because the software fails to validate input paths and handle symbolic links securely, malicious repositories can manipulate the host filesystem during standard CLI operations.
This vulnerability cluster is tracked as GHSA-WX3M-WHQV-XV47. The vulnerabilities present a High severity risk due to the potential for unauthorized local file exfiltration and local denial of service through file destruction. The issues are resolved in the 0.1.2 release.
The root cause of these vulnerabilities stems from four distinct programming oversights in skillctl related to path resolution and filesystem operations. The first flaw lies in the recursive copying helper function fs_util::copy_dir_all. When resolving directory entries, the code uses standard Rust filesystem APIs without checking whether a directory entry is a symbolic link. If an entry is a symbolic link to a file, the API evaluates is_dir() to false and falls back to standard file copying, which implicitly dereferences the link and copies the target content.
The second flaw is located in the serialization of the .skills.toml configuration file. The configuration parser deserializes destination and source_path directly into PathBuf structures without enforcing boundaries or performing lexical path validation. In Rust, joining an absolute path to an existing PathBuf completely replaces the base path, allowing an absolute destination path in the configuration file to hijack the entire filesystem path used during execution.
The third and fourth flaws exist in parameter handling. The --target argument in the detect subcommand and the user-defined fork names fail to validate relative path traversal sequences (..). By supplying traversal sequences, an attacker can escape the designated project directory root. When the utility attempts to clean or rename folders during synchronization, it deletes or overwrites directories outside the intended workspace.
An analysis of the vulnerable source code prior to the patch reveals how the recursive directory copying process fails to account for symbolic links. In the fs_util::copy_dir_all implementation, the code performs a standard directory traversal. It evaluates file types and executes a standard file copy operation when the item is not a directory.
// Vulnerable implementation in fs_util.rs (<= 0.1.1)
// If the entry is a symlink to a file, is_dir() evaluates to false,
// and fs::copy will dereference the symlink and copy the target file.
if entry.file_type()?.is_dir() {
copy_dir_all(&from, &to)?;
} else {
fs::copy(&from, &to)?; // Vulnerable: implicit dereference of symlinks
}The patch introduced in commit 827fff5c0698dd9e48e777d5907cf7bc19b91aca resolves this by querying symbolic link metadata explicitly before executing filesystem modifications. The updated implementation replaces the blind directory traversal with checks utilizing symlink_metadata and halts operations if a symbolic link is detected.
// Patched implementation in fs_util.rs (>= 0.1.2)
// The function now explicitly rejects symlinks to prevent dereferencing.
pub fn copy_dir_all(src: &Path, dst: &Path) -> Result<()> {
let src_meta = fs::symlink_metadata(src)?;
if src_meta.file_type().is_symlink() {
return Err(AppError::Config("refusing to copy symlink".into()));
}
// ...
for entry in fs::read_dir(src)? {
let entry = entry?;
let from = entry.path();
let to = dst.join(entry.file_name());
let file_type = entry.file_type()?;
if file_type.is_symlink() {
return Err(AppError::Config("refusing to copy nested symlink".into()));
}
if file_type.is_dir() {
copy_dir_all(&from, &to)?;
} else {
fs::copy(&from, &to)?; // Safe: symlinks have been actively blocked
}
}
Ok(())
}Exploitation of these vulnerabilities requires inducing an operator to run skillctl commands on a project containing a malicious configuration or a compromised skill library. In a file exfiltration scenario, an attacker publishes a repository containing a skill with a symbolic link. This symbolic link is designed to point to a known location of sensitive files on the operator's machine, such as /home/user/.aws/credentials or /etc/hostname.
When the operator adds the skill using the skillctl add command, the utility clones the repository and copies its contents. The application traverses the directories, encounters the symbolic link, treats it as a standard file due to the flawed file-type check, and copies the contents of the target sensitive file into the local project workspace. The next time the user runs a synchronization command like skillctl push, the copied file is uploaded to the remote repository.
In a directory destruction scenario, an attacker can modify the .skills.toml configuration file in a shared repository or via a Pull Request. By setting the destination field to an absolute path such as /home/victim/.ssh or a relative path with directory traversals such as ../../.ssh, the attacker forces the utility to execute filesystem operations outside the project root. When the victim runs skillctl pull, the replace_folder_contents function executes fs::remove_dir_all on the target directory, deleting the victim's local configurations.
The security impact of GHSA-WX3M-WHQV-XV47 is characterized by unauthorized disclosure of sensitive data and localized denial of service through file destruction. Because the tool runs with the privileges of the invoking user, the exploitation range is bounded only by the operating system permissions of the operator running the CLI utility.
The arbitrary file exfiltration vector allows external actors to target high-value assets. This includes configuration profiles, cryptographic keys, authentication tokens, and environment configurations stored on developers' machines. This exfiltration bypasses standard access controls by leveraging the legitimate write-back functionality of the tool during subsequent repository pushes.
The directory deletion vector presents a severe threat to operational integrity. A single automated pull request can cause irreversible loss of key directories on developer workstations. No specific host configurations or administrative privileges are required to exploit these flaws beyond standard command execution permissions.
The primary remediation strategy is the immediate upgrade of all skillctl installations to version 0.1.2 or later. The update introduces robust lexical path safety checks and explicitly rejects symbolic links during cloning and synchronization operations. Users can update their global installation by running cargo install skillctl --force.
If immediate upgrading is not feasible, operators must implement strict manual workarounds. Avoid running skillctl commands within untrusted repositories or merging pull requests that modify .skills.toml configurations without performing a manual security review of the proposed file paths.
Additionally, operators can inspect local systems for indicators of compromise. Search .skills.toml files for absolute paths or directory traversal sequences using text search utilities. Furthermore, search for symbolic links within downloaded skill libraries to ensure no links point to sensitive system folders.
| Product | Affected Versions | Fixed Version |
|---|---|---|
skillctl umanio-agency | >= 0.1.0, <= 0.1.1 | 0.1.2 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-22, CWE-61 |
| Attack Vector | Local, via malicious remote repository or pull request configurations |
| CVSS Severity | High (7.5) |
| Exploit Status | none |
| KEV Status | not listed |
SiYuan Note versions prior to v3.7.4 contain an information disclosure vulnerability in the `/api/asset/resolveAssetPath` endpoint. This endpoint returns absolute backend filesystem paths unmodified to CheckAuth-only requests. Low-privileged users or unauthenticated readers under publish mode can exploit this to leak the local directory layout, operating system username, and overall host deployment structure.
An access control vulnerability in the SiYuan personal knowledge management platform before version v3.7.4 exposes notebook encryption parameters to unauthenticated remote attackers. When the platform is configured in Publish Mode, specific API endpoints fail to enforce authorization checks. This access failure leaks key-derivation materials, password verifiers, and wrapped database keys to anonymous network clients.
A security vulnerability in the SiYuan local-first personal knowledge management system allows unauthenticated remote attackers to bypass logical boundary controls in publish (read-only) mode. By interacting with endpoints that lack proper publish-access validation, an attacker can disclose the application's internal database schemas and harvest block IDs across both public and private notebooks. This metadata leakage compromises the confidentiality of restricted documents and provides foundational information for targeted extraction.
An information disclosure vulnerability exists in the SiYuan personal knowledge management system versions prior to v3.7.4. The application fails to enforce publish-access filters on block attribute retrieval endpoints. Consequently, unauthenticated remote attackers can bypass document-level protection rules (such as password protection or disabled-publish flags) to retrieve sensitive block-level attributes, including aliases, memos, block names, and custom metadata fields, by querying the API using guessed or known block IDs.
An authentication bypass vulnerability (classified as CWE-288) exists in the publish-mode component of SiYuan, a Go-based note-taking application. This security flaw allows unauthenticated remote attackers to bypass password-protected note boundaries by leveraging auxiliary block endpoints that fail to enforce document access checks. Attackers can exploit this issue by first harvesting document metadata via a public search endpoint and subsequently fetching full rendered document contents using vulnerable block endpoints. This technical analysis explores the root cause, exploitation methodology, and remediation path.
An uncontrolled recursion vulnerability (CWE-674) in the toml-node NPM package (published as toml) prior to version 4.2.0 allows unauthenticated remote attackers to trigger process-wide Denial of Service (DoS) crashes. By submitting TOML payloads with deep bracket or brace nesting, attackers exhaust the V8 runtime stack limit.