Back to skill

Security audit

hash-check

Security checks for vulnerabilities and agentic risk

Overview

This hash-check skill is not clearly malicious, but it needs Review because its documented safeguards do not match the script and a manifest option can overwrite user-writable files.

Install only from a pinned, trusted source. Before using this skill on important data, be aware that gen mode writes immediately despite the dry-run wording, --manifest should be treated as a simple filename inside the target directory, and check mode may still pass when extra files have been added.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (4)

T08 · Insecure Dependencies

Warning
Location
SKILL.md:76
Finding
Unpinned Package Execution in the Recommended Installation Command## Vulnerability Details **File Location**: `SKILL.md:76-79` **Vulnerability Type**: Unpinned third-party package and repository installation **Risk Level**: Medium ### Vulnerable Code ```bash # One-click installation using the skills CLI npx skills add zhaoxinghua09-cell/agent-skills -g ``` ### Technical Analysis The recommended installation procedure invokes the `skills` package through `npx` without specifying an immutable package version or integrity hash. Depending on the local npm configuration and cache state, `npx` can retrieve and execute the latest published version of that package. The referenced skill repository is also identified by a mutable repository name rather than a commit hash or signed release. Consequently, neither the installation tool nor the installed repository content is cryptographically tied to the version reviewed in this audit. This creates a supply-chain trust boundary: compromise of the npm package, its maintainer account, the source repository, or related distribution infrastructure could cause users following the documented command to execute or install content that differs from the audited package. The audited project itself does not automatically run this command, and no existing compromise of the named package or repository was established. Exploitation therefore requires a supply-chain compromise and a user or Agent following the installation instructions. ### Attack Path 1. An attacker compromises the npm package used by `npx`, its publisher account, or the referenced source repository. 2. The attacker publishes a changed package version or replaces skill content in the mutable repository branch. 3. A user or Agent follows the installation command in `SKILL.md`. 4. `npx` downloads and executes the unpinned package under the invoking user's privileges. 5. The compromised installer executes arbitrary package lifecycle or application logic, or installs altered skills that run lat ...[truncated 420 chars]
Remediation
## Remediation Suggestions - Pin the CLI to a reviewed version, such as `npx skills@<exact-version>`, rather than resolving the latest release. - Pin installed repository content to an immutable commit hash or signed release tag. - Publish SHA-256 checksums or signed attestations for release artifacts and verify them before installation. - Use npm lockfiles and package integrity metadata where the installation workflow permits them. - Avoid recommending elevated execution. Document that installation should run with the minimum required privileges. - Periodically audit the pinned installer version and update it through a controlled review process.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/hash_check.py:18
Finding
Arbitrary User-Writable File Overwrite Through Manifest Path Traversal## Vulnerability Details **File Location**: `scripts/hash_check.py:18-29` **Vulnerability Type**: Unrestricted path resolution and file overwrite **Risk Level**: High ### Vulnerable Code ```python ap.add_argument("mode", choices=["gen", "check"], help="gen=生成清单 check=校验") ap.add_argument("--dir", required=True) ap.add_argument("--manifest", default="manifest.sha256") ap.add_argument("--json", action="store_true") a = ap.parse_args() if not os.path.isdir(a.dir): print("目录不存在: %s" % a.dir); sys.exit(2) cur = scan(a.dir) if a.mode == "gen": mpath = os.path.join(a.dir, a.manifest) with open(mpath, "w", encoding="utf-8") as f: for k in sorted(cur): f.write("%s %s\n" % (cur[k], k)) ``` ### Technical Analysis The value of `--manifest` is accepted without validation and passed to `os.path.join`. A value containing parent-directory components, such as `../../target`, can escape the directory selected by `--dir`. On supported platforms, an absolute `--manifest` value can also cause `os.path.join` to disregard the preceding directory entirely. In `gen` mode, the resulting path is opened with mode `"w"`. Python therefore creates the destination if it does not exist or immediately truncates an existing destination before writing the generated manifest. There is no canonical-path containment check, overwrite confirmation, exclusive creation, or atomic replacement process. The attacker cannot freely choose the written bytes because the output is constrained to hash-manifest records. Nevertheless, the attacker can destroy or corrupt any file writable by the process by replacing its contents with manifest data. ### Attack Path 1. An attacker influences an Agent workflow, wrapper script, copied command, or other input that controls the `--manifest` argument. 2. The attacker supplies a traversal or absolute path, for example: ```bash python scripts/hash_check.py gen --dir /path/t ...[truncated 743 chars]
Remediation
## Remediation Suggestions - Treat `--manifest` as a relative filename rather than an unrestricted path. - Reject absolute paths, parent-directory components, empty names, and platform-specific path prefixes. - Resolve both paths canonically and verify containment before opening the destination: ```python root = os.path.realpath(a.dir) mpath = os.path.realpath(os.path.join(root, a.manifest)) if os.path.commonpath([root, mpath]) != root: ap.error("--manifest must remain inside --dir") ``` - Consider permitting only a basename through a check such as `os.path.basename(value) == value`. - Refuse to overwrite an existing file unless the user explicitly provides a dedicated overwrite or apply flag. - Write to a securely created temporary file inside the destination directory, flush and synchronize it, and then atomically replace the intended manifest. - Run the utility with the minimum necessary filesystem permissions.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/hash_check.py:40
Finding
Integrity Verification Passes When Unmanifested Files Are Added## Vulnerability Details **File Location**: `scripts/hash_check.py:40-56` **Vulnerability Type**: Incomplete integrity validation **Risk Level**: Medium ### Vulnerable Code ```python missing = sorted(set(base) - set(cur)) added = sorted(set(cur) - set(base)) changed = sorted(k for k in set(base) & set(cur) if base[k] != cur[k]) ok = not missing and not changed if a.json: print(json.dumps({"ok": ok, "checked": len(base), "missing": missing, "added": added, "changed": changed}, ensure_ascii=False, indent=2)) else: print("校验: %d/%d 一致%s" % (len(base) - len(changed), len(base), " | PASS" if ok else " | FAIL")) for k in changed: print(" [改动] " + k) for k in missing: print(" [缺失] " + k) for k in added: print(" [新增] " + k) sys.exit(0 if ok else 1) ``` ### Technical Analysis The checker correctly calculates the `added` set but excludes that set from the success condition. As a result, a directory containing every expected file with the expected digest is considered valid even if it also contains arbitrary files absent from the trusted manifest. Added files are printed as informational output, but `ok` remains true and the process exits with status code 0. Automated systems commonly rely on the exit status or JSON `ok` field instead of parsing localized human-readable output, so they will treat this state as a successful integrity verification. This behavior conflicts with the stated purpose of comparing directory manifests and detecting tampering. It is especially relevant when the checked directory is later used as a package, deployment source, executable search location, or input to another Agent tool. The manifest itself is also scanned during checking. Because generation scans the directory before creating a new manifest, the generated manifest is normally absent from its own baseline and subsequently appears in `added`. The current omiss ...[truncated 1230 chars]
Remediation
## Remediation Suggestions - Make unexpected files fail strict verification: ```python ok = not missing and not added and not changed ``` - If additions must sometimes be allowed, make that behavior an explicit opt-in option such as `--allow-added`; retain strict verification as the default. - Exclude the selected manifest file from both generation and checking so it does not appear as an unmanifested addition or create self-referential behavior. - Ensure text output, JSON output, and exit codes all enforce the same policy. - Add regression tests covering added-only, missing-only, changed-only, and combined cases. - Test that an added file produces exit code 1 and `"ok": false` under the default policy.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/hash_check.py:18
Finding
Documented Dry-Run Protection Is Not Implemented## Vulnerability Details **File Location**: `scripts/hash_check.py:18-29` **Related Documentation**: `SKILL.md:47-50`, `README.md:3-5` **Vulnerability Type**: Misrepresented write-safety control and unconditional overwrite **Risk Level**: Medium ### Vulnerable Code The documentation states that write operations are previews unless `--apply` is provided: ```text - Supports `--json` machine-readable output - Operations that write to disk default to dry-run preview; add `--apply` to execute ``` The implementation defines no `--apply` option and writes immediately in `gen` mode: ```python ap.add_argument("mode", choices=["gen", "check"], help="gen=生成清单 check=校验") ap.add_argument("--dir", required=True) ap.add_argument("--manifest", default="manifest.sha256") ap.add_argument("--json", action="store_true") a = ap.parse_args() if not os.path.isdir(a.dir): print("目录不存在: %s" % a.dir); sys.exit(2) cur = scan(a.dir) if a.mode == "gen": mpath = os.path.join(a.dir, a.manifest) with open(mpath, "w", encoding="utf-8") as f: for k in sorted(cur): f.write("%s %s\n" % (cur[k], k)) ``` ### Technical Analysis Users are explicitly told that operations affecting disk default to a non-destructive preview and require `--apply` to make changes. The argument parser does not recognize `--apply`, and `gen` mode unconditionally opens the manifest with `"w"`. Opening an existing manifest this way truncates it immediately. Therefore, the documented safety boundary does not exist. An Agent or user relying on the documentation can unintentionally replace a trusted baseline without receiving a preview, confirmation prompt, backup, or overwrite warning. Replacing the trusted manifest can also undermine later integrity comparisons. If generation is mistakenly performed against a directory after unauthorized modifications, the new hashes become the accepted baseline. ### Attack Path 1. A us ...[truncated 925 chars]
Remediation
## Remediation Suggestions - Implement an actual `--apply` argument and make `gen` non-writing by default. - In dry-run mode, display the destination, number of records, whether the destination exists, and a summary of the intended changes without opening the file for writing. - Require `--apply` before creating or replacing the manifest. - Require an additional explicit overwrite option, or interactive confirmation, when the destination already exists. - Create a backup of an existing trusted manifest before replacement where appropriate. - Use an atomic temporary-file write and replacement procedure to prevent partial manifests. - If dry-run behavior is not desired, remove every dry-run and `--apply` claim from `SKILL.md` and `README.md`, and clearly document that `gen` writes immediately. - Add command-line tests proving that invocation without `--apply` leaves the filesystem unchanged.
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (9)

Vague Triggers

Medium
Confidence
83% confidence
Finding
The phrase "One command for daily file/text chores" is very broad and overlaps with many common tasks, without specifying concrete trigger phrases, constraints, or exclusions. In a markdown skill description, this can make it unclear when the skill should activate versus when a user's request is outside scope.

Lp3

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding
The skill advertises operational behavior that includes reading and potentially writing files, but it does not declare any tool scope such as permissions or allowed-tools. In an agent environment, missing scope declarations can cause the agent to invoke file capabilities more broadly than reviewers or users expect, increasing the chance of unintended filesystem access or modification.

Natural-Language Policy Violations

Medium
Confidence
88% confidence
Finding
The visible skill title and operating instructions are presented in Chinese, and the usage guidance for agents says to follow this SKILL.md workflow, but the document does not offer an English or locale-choice path for users. This can amount to a language-policy violation when a skill effectively requires a specific language without user opt-in.

Intent-Code Divergence

Medium
Confidence
91% confidence
Finding
The documentation describes generic write behavior, dry-run semantics, and `--apply` safeguards that do not clearly match the stated hash-check utility and its referenced script. This inconsistency can mislead users and agents about whether the skill writes to disk, causing unsafe assumptions during execution or review.

Rp1

Medium
Category
MCP Rug Pull
Confidence
82% confidence
Finding
The installation instruction references `npx skills` without pinning a specific version. This creates a supply-chain risk because users may execute whatever version is current at install time, including a compromised or breaking release, which is especially risky in agent tooling that can affect local files.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
This code file contains natural-language CLI descriptions and status messages in Chinese, starting with the argument parser description. The skill does not offer any user opt-in or language selection, which can violate a language/locale policy requiring user choice.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
From the mode help text through validation and result messages, the script consistently emits only Chinese text. Because no opt-in, fallback, or documented regional limitation is present, this is a natural-language policy concern rather than a security scanner issue.

Natural-Language Policy Violations

Low
Confidence
71% confidence
Finding
The README is bilingual and prominently uses Chinese in headings and descriptions, but it does not explicitly state that the user may choose their preferred language. Under the language/locale policy rule, forcing or assuming a language without opt-in can be a policy concern when no choice is documented.

Intent-Code Divergence

Low
Confidence
91% confidence
Finding
The manifest describes this skill narrowly as generating/verifying SHA-256 manifests for directory integrity checks. README line L07 instead claims it is for 'daily file/text chores,' which broadens the stated intent beyond hash verification and conflicts with the actual skill purpose.

Static analysis

No suspicious patterns detected.