Back to skill

Security audit

doc-desens-scanner

Security checks for vulnerabilities and agentic risk

Overview

This is a real local redaction scanner, but it needs review because it can expose sensitive prefixes in reports and does not return the documented failure code when it finds sensitive data.

Install only from a pinned, reviewed commit or release. Do not rely on the current exit code as a CI or publication gate until it returns nonzero on detections, and avoid --report for real secrets or PII because it prints plaintext prefixes that may be captured in logs.

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 (3)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/desens_scan.py:54
Finding
Detected sensitive content does not produce the documented failure exit status<![CDATA[ ## Vulnerability Details **File Location**: `scripts/desens_scan.py:54-59`; related contract in `SKILL.md:67` **Vulnerability Type**: Fail-open security gate **Risk Level**: High ### Vulnerable Code ```python masked = mask_text(text, hits, a.mask) print(masked) if a.report: rep = [{"type": n, "sample": f[:12] + ("…" if len(f) > 12 else "")} for n, _, f in hits] print("\n--- desens_report ---") print(json.dumps({"count": len(hits), "items": rep}, ensure_ascii=False, indent=2)) ``` The documented exit-status contract at `SKILL.md:67` states that a clean scan returns status `0`, detected issues return status `1`, and usage or environment errors return status `2`. The findings branch above reaches the end of `main()` without calling `sys.exit()`, raising `SystemExit`, or returning a status consumed by the entry point. Python therefore terminates with status `0` after sensitive content is found. ### Technical Analysis Security scanners used as publication or CI gates must fail closed. This implementation successfully identifies and masks findings but communicates success to the calling process. Human-readable output does not compensate for an incorrect process status because automation generally evaluates the exit code rather than parsing localized console messages. This behavior directly contradicts the documented interface and can allow a release pipeline to continue even when the scanner has detected credentials, PII, internal paths, or confidential project identifiers. ### Attack Path 1. A repository or publication candidate contains a value matched by one of the scanner rules. 2. A CI job invokes `desens_scan.py` as a release gate and relies on the documented exit-status contract. 3. The scanner finds the sensitive value, prints masked output, and reaches the end of `main()`. 4. Python exits with status `0`. 5. The CI system interprets the scan as successful and continues packaging or publishing the original artifact. 6. If the pipe ...[truncated 579 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Explicitly terminate with status `1` after processing one or more findings: ```python if hits: masked = mask_text(text, hits, a.mask) print(masked) if a.report: print_report(hits) raise SystemExit(1) ``` - Return status `0` only when no findings exist. - Catch expected file, encoding, and argument errors and return status `2` without exposing raw stack traces. - Refactor `main()` to return an integer and use `raise SystemExit(main())` at the entry point. - Add automated tests asserting all three documented statuses: - clean input returns `0`; - input containing a detectable item returns `1`; - invalid arguments or unreadable input return `2`. - Ensure release workflows scan the exact artifact that will be published or explicitly save and publish the sanitized output. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/desens_scan.py:56
Finding
Audit reports disclose plaintext prefixes of detected secrets and personal data<![CDATA[ ## Vulnerability Details **File Location**: `scripts/desens_scan.py:56-59` **Vulnerability Type**: Plaintext sensitive-data exposure through reports and logs **Risk Level**: Medium ### Vulnerable Code ```python if a.report: rep = [{"type": n, "sample": f[:12] + ("…" if len(f) > 12 else "")} for n, _, f in hits] print("\n--- desens_report ---") print(json.dumps({"count": len(hits), "items": rep}, ensure_ascii=False, indent=2)) ``` ### Technical Analysis For every finding, the report copies the first 12 characters of the original matched value into JSON and writes it to standard output. Values of 12 characters or fewer are disclosed completely. Longer values still expose a substantial plaintext prefix. This affects every supported finding class, including passwords, API keys, access tokens, email addresses, phone numbers, identity numbers, internal paths, and confidential project names. Standard output is commonly captured by terminal history, CI logs, observability platforms, build artifacts, or shell redirection. Consequently, the scanner can create an additional persistent copy of information it is intended to remove. Prefix disclosure can be particularly damaging for short passwords and identifiers. Token prefixes may also reveal the credential type, account context, or enough material to assist correlation and targeted guessing. ### Attack Path 1. A user scans a document containing a matched credential, PII value, internal path, or project identifier. 2. The user enables `--report`, potentially following the documentation's audit-trail claims. 3. The scanner copies up to the first 12 plaintext characters of each finding into the report. 4. The JSON report is printed to standard output. 5. A CI system, logging agent, shared terminal, or redirected output retains the disclosed fragments. 6. A user with access to those logs obtains complete short values or sensitive prefixes without needing access to the original document. ### Impa ...[truncated 514 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Remove the `sample` field and never include plaintext findings in reports. - Report non-sensitive metadata such as: - finding type; - line and column; - match length; - rule identifier; - sanitized file identifier. - If correlation between runs is required, use a keyed HMAC with a key held outside the report rather than an ordinary hash or plaintext prefix. - Write reports only to an explicitly selected destination with restrictive permissions. - Clearly document that standard output may be captured by external logging systems. - Add regression tests confirming that neither complete findings nor substrings of findings occur in report output. - Review existing logs and generated reports for sensitive fragments and remove them according to the applicable retention policy. ]]>

T08 · Insecure Dependencies

Warning
Location
SKILL.md:86
Finding
Installation instructions execute mutable and unpinned supply-chain content<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:86-89` **Vulnerability Type**: Unpinned package execution and mutable repository installation **Risk Level**: Medium ### Vulnerable Code ```bash # One-command acquisition through the skills CLI npx skills add zhaoxinghua09-cell/agent-skills -g # Manual alternative: clone and copy the skill git clone https://github.com/zhaoxinghua09-cell/agent-skills.git cp -r agent-skills/skills/doc-desens-scanner ~/.workbuddy/skills/ ``` The comments above are English translations of the source comments; the commands are reproduced unchanged. ### Technical Analysis The recommended command invokes `npx` without pinning the `skills` package to a reviewed version. Depending on local npm configuration and cache state, `npx` may download and execute package code resolved at installation time. The target skill repository is also referenced without a tag, commit hash, signed release, or artifact checksum. The manual alternative clones the repository's current default branch, which is mutable and can differ from the package that was audited. These instructions therefore do not ensure that users install the reviewed files. A compromised npm package, maintainer account, repository, release process, or upstream dependency could substitute different executable content after this audit. No evidence shows that the current package or repository is malicious. The vulnerability is the absence of provenance and version controls in an installation flow that can execute or install externally controlled content. ### Attack Path 1. An attacker compromises the npm package resolved as `skills`, its maintainer account, or the referenced repository. 2. The attacker publishes a modified package version or changes the repository's default branch. 3. A user follows the documented unpinned `npx` or `git clone` command. 4. The installation resolves the attacker's current content rather than the audited project snapshot. 5. The installe ...[truncated 727 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Pin the CLI to an explicitly reviewed version, such as `npx skills@<exact-version>`, and verify the package's publisher and integrity metadata. - Pin the Skill repository to an immutable commit hash or signed release tag. - Publish cryptographic checksums for reviewed release archives and require verification before installation. - Avoid global installation unless it is necessary; install into a scoped directory with least privilege. - Prefer downloading a signed release artifact over cloning a mutable default branch. - Document the exact package version, repository commit, expected checksums, and signature-verification procedure. - Add provenance controls such as signed commits, protected release branches, reproducible archives, and an SBOM. - Never instruct users to bypass npm integrity checks, TLS verification, signature checks, or operating-system security controls. ]]>
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
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (6)

Lp3

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding
The skill describes local scanning of documents and explicitly references file-oriented behavior, but it does not declare any tool scope such as permissions or allowed-tools. In an agent ecosystem, missing scope declarations can let the host or downstream agent infer broader file access than users expect, weakening least-privilege controls and making accidental over-read of sensitive files more likely.

Vague Triggers

Medium
Confidence
87% confidence
Finding
The manifest and summary say the skill should be used when a user says phrases like '先脱敏再发' or '对外发布前扫一遍隐私', and also when they '要把文档/代码/日志对外前做去敏时使用'. These are relatively broad conversational descriptions without clear exclusion conditions or tightly scoped trigger constraints, which increases the risk of unintended invocation in ordinary editing or review contexts.

Rp1

Medium
Category
MCP Rug Pull
Confidence
92% confidence
Finding
The installation instruction uses 'npx skills' without pinning a version or immutable package reference. That creates a supply-chain risk: a future malicious or compromised package version could be fetched and executed at install time, potentially leading to arbitrary code execution on the user's machine.

Natural-Language Policy Violations

Medium
Confidence
88% confidence
Finding
This file contains natural-language strings such as the module docstring, argument help, and console output exclusively in Chinese. Under the policy, forcing a specific language without offering a choice or documenting a justified locale constraint is a natural-language policy violation.

Natural-Language Policy Violations

Low
Confidence
88% confidence
Finding
The title is presented in Chinese first ("权属与原创性声明") and the document content is primarily Chinese, with no indication that users may choose another language or that a Chinese-only/localized format is required. Under the policy, language or locale constraints should be optional or explicitly justified.

Natural-Language Policy Violations

Low
Confidence
84% confidence
Finding
The manifest sets the category value to "AI安全", which imposes a specific language in user-facing metadata. Because the file does not indicate that the skill is intended only for a Chinese-language audience or provide any language/locale option, this can conflict with language/locale policy expectations.

Static analysis

No suspicious patterns detected.