Back to skill

Security audit

drawiodo

Security checks for vulnerabilities and agentic risk

Overview

This diagram skill is purpose-aligned, but it has under-scoped automatic local actions and concrete file-deletion/overwrite safety flaws that warrant review before installation.

Install only if you are comfortable with a local diagram tool that writes files, launches draw.io, and maintains/deletes local version folders automatically. Avoid using it on untrusted workspaces or preexisting .drawio_versions data until version-path validation, hook abort enforcement, and explicit confirmation for preview/pruning/restore are fixed.

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/drawio_version.py:135
Finding
Directory Traversal Enables Recursive Deletion Outside Version Storage<![CDATA[ ## Vulnerability Details **File Location**: `scripts/drawio_version.py:29-32`, `scripts/drawio_version.py:135-146`; equivalent cleanup logic also exists at `scripts/drawio_hooks.py:570-584` **Vulnerability Type**: Unvalidated path construction followed by recursive deletion **Risk Level**: High ### Vulnerable Code ```python def _version_dir(self, filepath: str, version: str) -> Path: """Get the directory for a specified version.""" filename = Path(filepath).stem return self.versions_dir / filename / version ``` ```python if changelog_path.exists(): with open(changelog_path, "r", encoding="utf-8") as f: changelog = json.load(f) else: changelog = [] changelog.append(meta) # Delete the oldest version when the configured limit is exceeded while len(changelog) > self.max_versions: oldest = changelog.pop(0) old_dir = self._version_dir(filepath, oldest["version"]) if old_dir.exists(): shutil.rmtree(old_dir) ``` The hook-based cleanup contains the same unsafe construction: ```python changelog = vm.list_versions(output_path) while len(changelog) >= max_versions: oldest = changelog.pop(0) old_dir = Path(vm.versions_dir) / Path(output_path).stem / oldest['version'] if old_dir.exists(): import shutil shutil.rmtree(old_dir) ``` ### Technical Analysis Version identifiers are loaded from the writable file: ```text .drawio_versions/<diagram-name>/changelog.json ``` The `version` property is treated as a trusted path component without format validation. `pathlib.Path` does not prevent traversal components such as `../`, and joining an absolute version path can discard the preceding base path entirely. The resulting path is passed to `shutil.rmtree`, which recursively deletes the resolved directory. No canonicalization or containment check verifies that the deletion target remains under the expected per-diagram version directory. Although ordinary application-generated versions use v ...[truncated 1240 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Strictly validate every version identifier before using it: ```python import re VERSION_PATTERN = re.compile(r"^v[1-9][0-9]*$") def validate_version(version: str) -> str: if not isinstance(version, str) or not VERSION_PATTERN.fullmatch(version): raise ValueError("Invalid version identifier") return version ``` 2. Resolve the expected parent and candidate target, then enforce containment: ```python parent = (self.versions_dir / Path(filepath).stem).resolve() candidate = (parent / validate_version(version)).resolve() if candidate.parent != parent: raise ValueError("Version path escapes its storage directory") ``` 3. Reject absolute paths, traversal components, symbolic links, and unexpected filesystem object types. 4. Treat `changelog.json` as untrusted input. Validate its schema, entry types, required fields, version syntax, and maximum number of records before performing filesystem operations. 5. Refuse deletion when validation fails rather than catching the error and reporting cleanup as successful. 6. Consolidate deletion logic in one hardened `VersionManager` method so the hook implementation cannot bypass validation. 7. Add regression tests using values such as `../target`, `../../target`, absolute paths, malformed JSON records, and symlinked version directories. Verify that no path outside the expected version root can be removed. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/drawio_agent.py:223
Finding
Ignored Hook Abort Results Bypass Mandatory Validation and Backup Controls<![CDATA[ ## Vulnerability Details **File Location**: `scripts/drawio_agent.py:223-288`; validator mismatch at `scripts/drawio_hooks.py:274-281`; backup abort behavior at `scripts/drawio_hooks.py:438-472` **Vulnerability Type**: Fail-open security-control implementation **Risk Level**: Medium ### Vulnerable Code The primary entry point invokes hooks but discards their results: ```python # pre_think hooks: input validation execute(HookPoint.PRE_THINK, {"input": text, "type": "text"}) if not output: workspace = Path(__file__).parent output = str(workspace / "output.drawio") ``` The caller also ignores mandatory backup failures and proceeds to overwrite the output: ```python # pre_iterate hooks: automatically back up an existing file is_update = os.path.exists(output) execute(HookPoint.PRE_ITERATE, { "output_path": output, "is_update": is_update }) filepath = builder.save(output) ``` The input validator expects a different context key and returns an abort result: ```python def _pre_think_validate(ctx: dict) -> dict: user_input = ctx.get('user_input', '') if not user_input or not user_input.strip(): return { 'success': False, 'message': 'input_validator: user input is empty; aborting workflow', 'abort': True, } return { 'success': True, 'message': f'input_validator: valid input ({len(user_input.strip())} chars)' } ``` Backup errors are also explicitly marked as abort conditions: ```python except Exception as e: return { 'success': False, 'message': f'auto_backup: backup failed: {e}', 'abort': True, } ``` ### Technical Analysis The hook framework returns a list of `HookResult` objects and represents mandatory blocking conditions with `abort=True`. The framework does not itself terminate the caller. The caller must inspect the returned results and stop the workflow. `generate_from_text` ignores all returned results. Conseque ...[truncated 1844 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Add a mandatory hook-execution wrapper that stops on any abort result: ```python def run_hooks_or_raise(point, context): results = execute(point, context) for result in results: if result.abort: raise RuntimeError( f"Workflow aborted by {result.name}: {result.message}" ) return results ``` 2. Replace security-sensitive calls with the blocking wrapper: ```python run_hooks_or_raise( HookPoint.PRE_THINK, {"user_input": text, "type": "text"} ) run_hooks_or_raise( HookPoint.PRE_ITERATE, {"output_path": output, "is_update": is_update} ) ``` 3. Standardize hook context schemas. Use `user_input` consistently, preferably with typed context objects or constants rather than free-form dictionary keys. 4. Ensure the output write occurs only after all pre-iteration hooks complete successfully. 5. For existing files, use an atomic workflow: - Create and verify the backup. - Write the new diagram to a temporary file in the same directory. - Validate the generated file. - Atomically replace the destination with `os.replace`. 6. Apply the same abort handling to post-think, confirmation, post-iteration, and version-control hook calls where their results affect correctness or safety. 7. Add tests proving that: - Empty input prevents generation. - A pre-think abort prevents all writes. - A backup failure prevents overwrite. - No post-hook is executed after a blocking pre-hook failure. - Context-key mismatches fail tests rather than silently disabling controls. ]]>
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Output HandlingUnvalidated Output Injection, Cross-Context Output, Unbounded Output
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (81)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
This skill explicitly states that generated files are automatically opened in draw.io, which implies execution of a local GUI application and file writes. In a high-permission skill, undocumented or insufficiently constrained local process launching and fixed-path output can create unsafe side effects, surprise execution, or exposure to path misuse if implementation does not strictly validate destinations and require user consent.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
This skill explicitly states that generated files are automatically opened in draw.io, which implies execution of a local GUI application and file writes. In a high-permission skill, undocumented or insufficiently constrained local process launching and fixed-path output can create unsafe side effects, surprise execution, or exposure to path misuse if implementation does not strictly validate destinations and require user consent.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
This skill explicitly states that generated files are automatically opened in draw.io, which implies execution of a local GUI application and file writes. In a high-permission skill, undocumented or insufficiently constrained local process launching and fixed-path output can create unsafe side effects, surprise execution, or exposure to path misuse if implementation does not strictly validate destinations and require user consent.

Tp4

High
Category
MCP Tool Poisoning
Confidence
89% confidence
Finding
This skill explicitly states that generated files are automatically opened in draw.io, which implies execution of a local GUI application and file writes. In a high-permission skill, undocumented or insufficiently constrained local process launching and fixed-path output can create unsafe side effects, surprise execution, or exposure to path misuse if implementation does not strictly validate destinations and require user consent.

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding
This skill explicitly states that generated files are automatically opened in draw.io, which implies execution of a local GUI application and file writes. In a high-permission skill, undocumented or insufficiently constrained local process launching and fixed-path output can create unsafe side effects, surprise execution, or exposure to path misuse if implementation does not strictly validate destinations and require user consent.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
This skill explicitly states that generated files are automatically opened in draw.io, which implies execution of a local GUI application and file writes. In a high-permission skill, undocumented or insufficiently constrained local process launching and fixed-path output can create unsafe side effects, surprise execution, or exposure to path misuse if implementation does not strictly validate destinations and require user consent.

Tp4

High
Category
MCP Tool Poisoning
Confidence
91% confidence
Finding
This skill explicitly states that generated files are automatically opened in draw.io, which implies execution of a local GUI application and file writes. In a high-permission skill, undocumented or insufficiently constrained local process launching and fixed-path output can create unsafe side effects, surprise execution, or exposure to path misuse if implementation does not strictly validate destinations and require user consent.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
This skill explicitly states that generated files are automatically opened in draw.io, which implies execution of a local GUI application and file writes. In a high-permission skill, undocumented or insufficiently constrained local process launching and fixed-path output can create unsafe side effects, surprise execution, or exposure to path misuse if implementation does not strictly validate destinations and require user consent.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
This skill explicitly states that generated files are automatically opened in draw.io, which implies execution of a local GUI application and file writes. In a high-permission skill, undocumented or insufficiently constrained local process launching and fixed-path output can create unsafe side effects, surprise execution, or exposure to path misuse if implementation does not strictly validate destinations and require user consent.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
This skill explicitly states that generated files are automatically opened in draw.io, which implies execution of a local GUI application and file writes. In a high-permission skill, undocumented or insufficiently constrained local process launching and fixed-path output can create unsafe side effects, surprise execution, or exposure to path misuse if implementation does not strictly validate destinations and require user consent.

Ae1

High
Category
analysis-evasion
Content
> 📚 **渐进式加载**:本技能采用渐进式 MD 体系,`SKILL.md` 为入口(≤230行),详细内容拆分到 `references/*.md` 按需加载。
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
| `scripts/drawio_hooks.py` | 钩子系统 | 8 个 Hook Point 实现 | 无 |
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Missing User Warnings

High
Confidence
96% confidence
Finding
The documentation describes automatic deletion of the oldest version data and logs when `version_count >= max_versions`, but does not present a clear user warning, confirmation flow, or retention policy disclosure. In a diagram/versioning workflow this can cause silent, irreversible data loss, especially because the feature is framed as automatic and outside LLM control.

Missing User Warnings

High
Confidence
97% confidence
Finding
The hook automatically deletes version directories when a limit is reached, without an explicit user warning or recovery check. In a version-control feature this can destroy historical data unexpectedly, and because paths are derived from output_path and VersionManager state, mistakes or path-handling flaws upstream could turn routine use into destructive file loss.

Unvalidated Output Injection

High
Category
Output Handling
Content
drawio_path = r"C:\Program Files\draw.io\draw.io.exe"
if os.path.exists(drawio_path):
    for theme in themes:
        subprocess.Popen([drawio_path, os.path.join(OUTPUT, f"theme_{theme}.drawio")])
    print("📂 全部已打开")
Confidence
95% confidence
Finding
Model output is used without validation or sanitization. Unvalidated output injected into downstream contexts (SQL, shell, HTML) enables injection attacks and arbitrary code execution.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The skill advertises automatic opening of generated files in draw.io but does not prominently warn users in the description that it will launch a local application. Unexpected local process execution is a meaningful security and safety concern because it changes system state and may open attacker-influenced content without explicit, informed consent.

Natural-Language Policy Violations

Medium
Confidence
81% confidence
Finding
The skill description and invocation guidance are entirely written as a Chinese-language interaction model ('自动做图', trigger examples in Chinese) without indicating that other languages are supported or that the user may choose their preferred language. Under the policy, forcing a specific language without opt-in is a natural-language policy concern.

Vague Triggers

Medium
Confidence
90% confidence
Finding
The description says the skill triggers when a user asks to 'draw, generate charts, make architecture diagrams, flowcharts, UML, ER, sequence diagrams, mind maps, etc.', which is broad enough to match many common requests and can cause unintended activation. In an agent setting, over-broad activation increases the chance that the skill handles requests outside its intended scope, leading to confusing behavior, unwanted file generation, or unsafe downstream actions such as automatically opening generated content.

Natural-Language Policy Violations

Medium
Confidence
83% confidence
Finding
The description is written as Chinese-only behavior ('draw.io 自动做图 Skill') without indicating that the language is user-selectable or that the skill adapts to user preference. While not directly a code-execution issue, forced language behavior can mislead users, degrade transparency, and cause the agent to respond or generate artifacts in an unexpected language, which is a safety and usability risk in automated workflows.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The file is entirely in Chinese and does not provide a language selection mechanism or document a hard locale requirement. In a security-sensitive workflow, forcing a single language can cause users or downstream agents to misunderstand operational constraints, confirmations, or safety guidance, which may lead to misuse or unsafe execution.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
The file's headings and descriptive entries are predominantly in Chinese, which effectively forces a specific language for users reading the skill documentation. Under the stated policy, a language constraint should either offer user choice or be clearly documented as a justified locale-specific requirement.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The shortcut mode is described as directly clearing confirmation options so the LLM cannot ask the user a confirmation question. This weakens an important consent and review checkpoint in a workflow that can create files, launch applications, and modify versions, increasing the chance of unintended actions being taken without user awareness.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The changelog documents a hook that automatically deletes the oldest version when version limits are exceeded, with no indication of explicit user notice, consent, or recovery safeguards. In a diagram-generation skill with versioning and iterative edits, silent deletion can cause unexpected data loss and makes it easier for users to lose important work without realizing the tool is performing destructive actions.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The FAQ instructs users to restore prior versions using a restore command but does not warn that this operation modifies the current file state and can overwrite newer work. In a skill that automatically manages diagram files and versions, omission of overwrite/rollback warnings can lead to unintended data loss or unsafe file changes, especially if the agent executes the command on the user's behalf.

Natural-Language Policy Violations

Medium
Confidence
91% confidence
Finding
This markdown file contains user-facing natural-language instructions solely in Chinese, and there is no indication that the skill is region-specific or that users may opt into another language. Under the language/locale policy rule, forcing a specific language without opt-in is a policy concern.

Static analysis

No suspicious patterns detected.