Back to skill

Security audit

Aicodem skill

Security checks for vulnerabilities and agentic risk

Overview

The skill has a legitimate XMind test-case generator purpose, but its script can be directed to overwrite arbitrary writable files through an underdocumented output path.

Review before installing if this skill may run in workspaces with important writable files. It should be constrained to write only a new .xmind file inside a dedicated output directory, and output_file should either be removed from caller control or explicitly declared and validated.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/generate_xmind.py:287
Finding
Arbitrary File Overwrite Through an Unvalidated Output Path<![CDATA[ ## Vulnerability Details **File Location**: `scripts/generate_xmind.py`, lines 287 and 312–318 **Vulnerability Type**: Arbitrary file overwrite / path traversal **Risk Level**: Medium ### Vulnerable Code ```python # scripts/generate_xmind.py:287 with zipfile.ZipFile(output_file, 'w', zipfile.ZIP_DEFLATED) as zf: zf.writestr('content.xml', content_xml) zf.writestr('styles.xml', styles_xml) zf.writestr('comments.xml', comments_xml) zf.writestr('META-INF/manifest.xml', manifest_xml) ``` The skill entry point passes the caller-controlled path directly to this file-writing operation: ```python # scripts/generate_xmind.py:305-318 def run(input_data): """ Skill entry point invoked by OpenClaw. """ test_data = input_data.get("test_data", DEFAULT_TEST_DATA) output_file = input_data.get("output_file", "测试用例.xmind") if isinstance(test_data, str): test_data = json.loads(test_data) result = generate_xmind(test_data, output_file) return result ``` The command-line interface exposes the same behavior: ```python # scripts/generate_xmind.py:325-335 output_file = sys.argv[2] if len(sys.argv) > 2 else "测试用例.xmind" if input_file: with open(input_file, 'r', encoding='utf-8') as f: test_data = json.load(f) else: test_data = DEFAULT_TEST_DATA result = generate_xmind(test_data, output_file) ``` ### Technical Analysis The `output_file` value is used without path normalization, directory confinement, extension validation, symlink checks, or overwrite authorization. Python's `zipfile.ZipFile` with mode `'w'` creates the specified file or truncates an existing file before writing the XMind ZIP archive. Consequently, a caller can supply: - An absolute path. - A relative path containing parent-directory traversal components. - A path to an existing writable file. - Potentially a path resolving through a symbolic link. Although `output_file` is not declared in `skill.yaml`, the Python `run()` func ...[truncated 2082 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Create a dedicated output directory controlled by the skill and resolve all output paths relative to it. 2. Reject absolute paths and verify that the normalized destination remains inside the approved directory: ```python from pathlib import Path OUTPUT_DIR = Path("outputs").resolve() OUTPUT_DIR.mkdir(parents=True, exist_ok=True) requested_name = Path(output_file) if requested_name.is_absolute(): raise ValueError("Absolute output paths are not permitted") destination = (OUTPUT_DIR / requested_name).resolve() if OUTPUT_DIR not in destination.parents: raise ValueError("Output path escapes the approved directory") if destination.suffix.lower() != ".xmind": raise ValueError("Output file must use the .xmind extension") ``` 3. Prefer accepting only a basename rather than an arbitrary path. 4. Reject existing targets by opening with exclusive creation semantics, or require a separate explicit overwrite option. 5. Check parent directories and target components for symbolic links before writing. Where feasible, use platform-supported no-follow file operations. 6. Generate the archive in a securely created temporary file within the approved directory, then atomically rename it to the validated destination. 7. Add `output_file` to `skill.yaml` only if caller selection is required. Constrain it with a filename-only pattern and document its security restrictions. Otherwise, remove caller control and always generate a server-assigned filename. 8. Run the skill under a least-privileged account with write access limited to its designated output directory. 9. Add tests covering absolute paths, parent traversal, nested traversal, symlink targets, existing files, invalid extensions, and normal output generation. ]]>
Vulnerability Patterns
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (4)

Lp3

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding
Without declared permissions the skill's intent is opaque and cannot be validated.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
The manifest description forces a specific language for user-facing skill metadata, but does not offer any user opt-in or indicate that the skill is intentionally limited to a Chinese-speaking audience. This can violate language or locale policy for skills expected to be broadly usable.

Natural-Language Policy Violations

Low
Confidence
84% confidence
Finding
The description is written only in Chinese ("XMind 测试用例生成器"), which may indicate a language-specific skill presentation without offering any user choice or opt-in. Under the policy, forcing a specific language can be a natural-language policy violation unless the locale restriction is explicitly documented and justified.

Natural-Language Policy Violations

Low
Confidence
93% confidence
Finding
This JSON file contains natural-language test case names, preconditions, steps, and expected results entirely in Chinese. Under the stated policy, forcing a specific language without user opt-in can be a locale-policy violation, and the file provides no indication of language choice or justified regional scope.

Static analysis

No suspicious patterns detected.