Back to skill

Security audit

Use when user wants to review material forms for data sharing catalogs, field completeness, platform consistency, and issue-list output. Triggers include「材料审核」「共享清单审核」「检查文档审查」「平台对接核对」「编目一致性检查」.

Security checks for vulnerabilities and agentic risk

Overview

The skill matches its stated document-review purpose, but its audit script can persist sensitive database and contact details, including passwords, in plaintext output files.

Install only if you are comfortable with local plaintext audit artifacts. Do not run it on submissions containing live database passwords or secrets unless the output directory is access-controlled and retention is managed; prefer redaction or a password-presence-only check before using it on real operational materials.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/material_review_audit.py:37
Finding
Plaintext Database Passwords May Be Copied into Audit Output## Vulnerability Details **File Location**: `scripts/material_review_audit.py:37, 156-177, 471-480, 594-601` **Vulnerability Type**: Plaintext sensitive-data exposure **Risk Level**: High ### Complete Code Snippet ```python BASIC_FIELD_ALIASES: Dict[str, List[str]] = { # ... "database_password_note": ["密码"], } ``` ```python def _extract_basic_info(lines: List[str], tables: List[List[List[str]]]) -> Dict[str, str]: result: Dict[str, str] = {} # First pass: from table key-value pairs. kv = _extract_kv_from_tables(tables) for raw_label, raw_value in kv.items(): k = _match_alias(raw_label, BASIC_FIELD_ALIASES) if k and raw_value: result[k] = raw_value # Second pass: line-based fallback. for idx, line in enumerate(lines): key = _match_alias(line, BASIC_FIELD_ALIASES) if not key: continue value = _value_after_colon(line) if not value and idx + 1 < len(lines): nxt = lines[idx + 1] if not _looks_like_label(nxt): value = normalize_text(nxt) if value: result[key] = value return result ``` ```python structured: Dict[str, object] = { "source": { "submission_docx": str(submission_path), "template_docx": str(template_path), "review_rule_docx": str(rule_path), }, "template_items": sorted(set([x for x in tpl_lines if len(x) <= 40])), "basic_info": _extract_basic_info(sub_lines, sub_tables), "data_resources": [r.__dict__ for r in _extract_resources(sub_lines, sub_tables)], "rule_points": rule_lines, } ``` ```python structured_path.write_text( json.dumps(structured, ensure_ascii=False, indent=2), encoding="utf-8", ) ``` ### Technical Analysis The parser explicitly recognizes a document field labeled as a password and stores its value under `database_password_note`. The extracted value is retained unchanged in `basic_info` and serialized into `structu ...[truncated 1358 chars]
Remediation
## Remediation Suggestions 1. Remove password-related aliases from the extraction schema unless the field's presence must be validated. 2. If presence validation is required, record only a Boolean indicator such as `password_provided: true`; never retain the value. 3. Apply centralized redaction before serialization so fields matching password, secret, token, key, or credential patterns become `[REDACTED]`. 4. Exclude sensitive fields from generated reports, logs, exceptions, and debugging output. 5. Create output files with owner-only permissions, such as mode `0600`, and create the output directory with mode `0700`. 6. Document that users must not place live credentials in review materials and should use a secure secret-delivery channel for operational handoff. 7. Review and securely delete previously generated artifacts that may contain plaintext credentials.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/material_review_audit.py:100
Finding
Unbounded DOCX Decompression and XML Parsing Enables Resource Exhaustion## Vulnerability Details **File Location**: `scripts/material_review_audit.py:100-104` **Vulnerability Type**: Uncontrolled resource consumption when parsing untrusted files **Risk Level**: Medium ### Complete Code Snippet ```python def _extract_docx(path: Path) -> Tuple[List[str], List[List[List[str]]]]: with zipfile.ZipFile(path, "r") as zf: xml_bytes = zf.read("word/document.xml") root = ET.fromstring(xml_bytes) body = root.find(".//w:body", W_NS) if body is None: return [], [] ``` ### Technical Analysis A DOCX document is a ZIP archive containing XML files. The implementation reads the entire expanded `word/document.xml` member into memory and then constructs an in-memory XML tree. It does not enforce limits on: - Archive or compressed-member size - Expanded XML size - Compression ratio - XML element count or nesting depth - Parsing time or total process memory Although Python's standard XML parser mitigates some traditional entity-expansion attacks, it does not prevent resource exhaustion caused by a very large expanded document or an XML structure designed to require excessive memory and CPU. ### Attack Path 1. An attacker prepares a syntactically valid DOCX containing an extremely large or highly compressed `word/document.xml`. 2. The attacker submits the document for material review. 3. `zipfile.ZipFile.read()` expands the complete XML member into memory without checking its resulting size or compression ratio. 4. `ET.fromstring()` builds an additional in-memory element tree. 5. The process consumes excessive memory or CPU and may stall, be terminated, or disrupt concurrent reviews. ### Impact Assessment Successful exploitation affects the availability of the audit process under the privileges of the account running the Skill. It may cause process termination, prolonged CPU consumption, memory exhaustion, or disruption of other workloads sharing the same host or container. The code shown does not grant the atta ...[truncated 148 chars]
Remediation
## Remediation Suggestions 1. Inspect `ZipInfo` metadata before extraction and reject `word/document.xml` when its expanded size exceeds a conservative limit. 2. Reject archives with suspicious compression ratios or excessive aggregate expanded size. 3. Read the XML member incrementally with an explicit byte limit rather than calling `zf.read()` without bounds. 4. Use streaming XML parsing and clear processed elements to reduce peak memory consumption. 5. Enforce maximum document dimensions, including element count, text length, table count, row count, and nesting depth. 6. Process untrusted documents in an isolated worker with strict memory, CPU, and execution-time limits. 7. Catch malformed archive and XML exceptions and return a controlled validation error rather than allowing an uncontrolled crash. 8. Add regression tests using oversized, highly compressed, deeply nested, and malformed DOCX samples.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (8)

Lp3

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding
The skill advertises an internal audit script that produces output files, but the manifest does not declare any explicit tool scope or permissions limiting file-write behavior. In an agent environment, undeclared write capability weakens least-privilege controls and can let the skill create or overwrite files in ways that are not obvious to reviewers or users.

Natural-Language Policy Violations

Medium
Confidence
88% confidence
Finding
The manifest description and main skill content are written entirely in Chinese and define only Chinese trigger phrases, with no indication that users may interact in other languages or that the locale restriction is intentional. Under the policy rule, forcing a specific language without user opt-in is a natural-language policy concern.

Natural-Language Policy Violations

Medium
Confidence
90% confidence
Finding
The entire skill reference is written as Chinese-only instructions and reusable review prompts, with no indication that users may choose another language or that the skill is limited to a Chinese-specific regulatory or regional context. Under the stated policy, forcing a specific language without opt-in is a natural-language policy violation.

Natural-Language Policy Violations

Medium
Confidence
97% confidence
Finding
Lines L23-L25 require that every data item have a Chinese description and prohibit matching the English field name. This is a natural-language locale requirement, and the file does not offer any opt-in, alternative language support, or region-specific justification.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The script extracts full submission contents from potentially sensitive .docx materials and writes structured_data.json, issues.json, and a markdown report to disk by default. Because the material includes contact details, system information, database connection metadata, and review results, storing these artifacts without explicit warning, minimization, or protective controls increases the risk of local data exposure, accidental retention, or leakage to other users/processes on the same host.

Natural-Language Policy Violations

Low
Confidence
92% confidence
Finding
This markdown file contains user-facing instructions exclusively in Chinese, and there is no indication that users can opt into another language or that the skill is intentionally limited to a Chinese-speaking context. Under the policy rules, forcing a specific language without opt-in can be a natural-language policy violation.

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Content
continue
        # Put fallback values into first resource unless already present.
        target = resources[0]
        if not getattr(target, k, "") and raw_value:
            setattr(target, k, raw_value)

    # Parse field definition tables and attach by order.
Confidence
50% confidence
Finding
Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Content
loc_prefix = f"数据资源{res.index}"

        for field_name in REQUIRED_RESOURCE_FIELDS:
            value = normalize_text(getattr(res, field_name, ""))
            if not value:
                issues.append(
                    {
Confidence
50% confidence
Finding
Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Static analysis

No suspicious patterns detected.