Back to skill

Security audit

项目流程管理器

Security checks for vulnerabilities and agentic risk

Overview

This is a local project-management skill, but unsafe path handling can let project IDs read or overwrite JSON and generated files outside the intended project folders.

Review before installing. Use this only in a trusted workspace, avoid project IDs containing slashes or '..', and do not open generated HTML boards from project data supplied by untrusted people. Treat reports, boards, project JSON, and email drafts as potentially sensitive local business files.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/generate_board.py:153
Finding
Stored HTML Injection in Generated Project Boards<![CDATA[ ## Vulnerability Details **File Location**: `scripts/generate_board.py`, lines 153–221 **Vulnerability Type**: Stored HTML injection / cross-site scripting **Risk Level**: Medium ### Vulnerable Code ```python html = f'''<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>{project['name']} - 项目看板</title> ... <body> <div class="header"> <h1>📊 {project['name']}</h1> ... <div class="task"> <div class="task-title">{t['name']}</div> <div class="task-meta">负责人: {t.get('assignee', '未分配')} | 截止: {t.get('endDate', '未设置')}</div> </div> ... <div class="task"> <div class="task-title">{t['name']}</div> <div class="task-meta">负责人: {t.get('assignee', '未分配')}</div> <div class="task-progress"> <div class="task-progress-bar" style="width: {t.get('progress', 0)}%"></div> </div> ... <div class="task"> <div class="task-title">{t['name']}</div> <div class="task-meta">负责人: {t.get('assignee', '未分配')}</div> <div class="task-meta" style="color: #f44336;">阻塞: {', '.join(t.get('blockers', []))}</div> </div> ``` ### Technical Analysis The HTML board generator interpolates project data directly into an HTML document without context-appropriate escaping. Untrusted fields include the project name, task name, assignee, end date, blockers, and progress value. Several of these fields can be supplied through normal command-line operations and are persisted in project JSON files. An attacker able to influence project data can inject arbitrary HTML elements or event handlers. The payload becomes persistent because it is stored in the project data and reproduced whenever an HTML board is generated. For example, a task name containing the following value would be inserted directly into the document: ```html <img src=x onerror="alert('inj ...[truncated 1519 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Escape every text value before inserting it into HTML: ```python from html import escape safe_project_name = escape(str(project.get("name", "")), quote=True) safe_task_name = escape(str(t.get("name", "")), quote=True) safe_assignee = escape(str(t.get("assignee", "Unassigned")), quote=True) safe_end_date = escape(str(t.get("endDate", "Not set")), quote=True) safe_blockers = escape(", ".join(map(str, t.get("blockers", []))), quote=True) ``` 2. Validate numeric values separately before placing them into CSS: ```python progress = t.get("progress", 0) if not isinstance(progress, (int, float)): progress = 0 progress = max(0, min(100, progress)) ``` 3. Prefer a templating engine with automatic HTML escaping enabled rather than constructing the complete document with f-strings. 4. Add a restrictive Content Security Policy, preferably disallowing inline scripts and event handlers: ```html <meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; img-src data:"> ``` 5. Validate the complete loaded project schema before rendering it, even when the JSON file is expected to have been created by another project script. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/generate_board.py:16
Finding
Project Identifier Path Traversal Allows Access Outside the Projects Directory<![CDATA[ ## Vulnerability Details **File Location**: `scripts/add_department.py:21`, `scripts/add_milestone.py:21`, `scripts/add_task.py:22`, `scripts/generate_board.py:16`, `scripts/generate_report.py:16`, `scripts/send_reminder.py:16`, `scripts/update_task.py:16`, and `scripts/view_project.py:14` **Vulnerability Type**: Path traversal leading to unauthorized local file access and modification **Risk Level**: High ### Vulnerable Code The same unsafe path construction is repeated across the affected scripts: ```python project_file = Path("projects") / f"{project_id}.json" if not project_file.exists(): print(f"❌ 项目不存在: {project_id}") return None with open(project_file, 'r', encoding='utf-8') as f: project = json.load(f) ``` Mutation commands subsequently write to the same attacker-controlled path. For example, `scripts/update_task.py` contains: ```python project_file = Path("projects") / f"{project_id}.json" with open(project_file, 'r', encoding='utf-8') as f: project = json.load(f) # Project data is modified here. with open(project_file, 'w', encoding='utf-8') as f: json.dump(project, f, ensure_ascii=False, indent=2) ``` ### Technical Analysis The positional `project_id` argument is controlled by the command-line caller and is concatenated into a filesystem path without validation. `pathlib.Path` does not automatically prevent traversal sequences. For example: ```text project_id = ../../target ``` produces a path equivalent to: ```text projects/../../target.json ``` The operating system resolves the `..` components, allowing the script to access a JSON file outside the intended `projects/` directory. Read-oriented commands can parse and display information from an arbitrary accessible JSON file. Commands that mutate projects may write altered data back to the traversed file if its structure is compatible with the expected project schema. ### Attack Path 1. The attacker identifies an accessible JSON file outside `projects/ ...[truncated 1482 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Restrict project identifiers to a conservative allowlist: ```python import re PROJECT_ID_PATTERN = re.compile(r"^[A-Za-z0-9_-]+$") if not PROJECT_ID_PATTERN.fullmatch(project_id): raise ValueError("Invalid project identifier") ``` 2. Resolve the base directory and candidate path, then enforce containment: ```python projects_dir = Path("projects").resolve() project_file = (projects_dir / f"{project_id}.json").resolve() if project_file.parent != projects_dir: raise ValueError("Project path escapes the projects directory") ``` 3. Place path validation in a shared helper and use it in every script rather than duplicating unsafe path construction. 4. Open files with explicit expectations and handle symbolic links. Where the platform permits, use directory-relative file operations with protections against following symlinks. 5. Validate the loaded JSON against a defined project schema before displaying or modifying it. 6. Use atomic writes for mutation commands: write validated content to a temporary file in the same protected directory, flush it, and atomically replace the intended project file. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/generate_board.py:131
Finding
Stored Project ID Controls Generated Board Output Path<![CDATA[ ## Vulnerability Details **File Location**: `scripts/generate_board.py`, lines 131–135 and 243–247 **Vulnerability Type**: Path traversal leading to file creation or overwrite **Risk Level**: Medium ### Vulnerable Code Markdown output: ```python # 保存文件 boards_dir = Path("boards") boards_dir.mkdir(exist_ok=True) board_path = boards_dir / f"{project['id']}-board.md" with open(board_path, 'w', encoding='utf-8') as f: f.write(content) ``` HTML output: ```python # 保存文件 boards_dir = Path("boards") boards_dir.mkdir(exist_ok=True) board_path = boards_dir / f"{project['id']}-board.html" with open(board_path, 'w', encoding='utf-8') as f: f.write(html) ``` ### Technical Analysis The output filename is derived from `project['id']`, which is read from project JSON and is not validated before use. A stored identifier containing path separators or `..` components can cause the generated output path to escape the intended `boards/` directory. For example, a stored value such as: ```json { "id": "../outside" } ``` causes the HTML output path to resolve as: ```text boards/../outside-board.html ``` The project identifier supplied on the command line and the identifier stored inside the loaded JSON are independent. Therefore, validation of only the command-line lookup value would not fix this output vulnerability. ### Attack Path 1. An attacker creates or modifies a project JSON file and assigns a traversal value to its `id` property. 2. The victim invokes the board generator using the filename-based project identifier: ```bash python3 scripts/generate_board.py PROJECT_ID --format html ``` 3. The script loads the JSON and passes it to `generate_html_board()` or `generate_markdown_board()`. 4. The generator constructs the destination from the untrusted stored `project['id']`. 5. The filesystem resolves the traversal sequence. 6. The generated board is written outside `boards/`, overwriting an existing file if the resolved destination an ...[truncated 772 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not use the identifier stored inside project data as a filesystem path component. 2. Use a separately validated filename derived from the command-line project identifier or an internally generated opaque identifier. 3. Apply a strict allowlist to every stored identifier before use: ```python import re stored_id = str(project.get("id", "")) if not re.fullmatch(r"[A-Za-z0-9_-]+", stored_id): raise ValueError("Unsafe stored project identifier") ``` 4. Resolve the destination and verify that it remains directly within the board directory: ```python boards_dir = Path("boards").resolve() boards_dir.mkdir(exist_ok=True) board_path = (boards_dir / f"{stored_id}-board.html").resolve() if board_path.parent != boards_dir: raise ValueError("Board output path escapes the board directory") ``` 5. Reject symbolic-link destinations and use atomic file creation or replacement where supported. 6. Apply equivalent containment checks to every generated report, email draft, and board path throughout the project. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (18)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
声明描述的是一个功能较完整的项目管理系统,覆盖项目全生命周期中的多项核心能力。但提供的代码片段只负责初始化项目文件并预填充模板化的部门和里程碑数据,属于项目管理工具中的一个子功能。虽然数据结构中预留了 tasks、kpis、reports 等字段,与声明场景有一定相关性,但并没有实现这些能力本身,也没有邮件、报表、看板或预警等行为。因此,代码实际行为与声明用途相比明显更窄,构成描述与行为不匹配。

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
Yes, this is a mismatch. The description claims a substantial project management capability set, but the code chunk does not implement any of those behaviors. It is merely a stub/example script with a print statement and TODO comments. There are no undeclared dangerous capabilities present; the mismatch is that the declared functionality is not actually implemented in the provided code.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
The declared description presents a comprehensive project management tool with multiple operational capabilities such as milestone planning, cross-department coordination, KPI tracking, reporting, email reminders, and dashboard creation. The supplied code only lists locally stored project records from JSON files, optionally filters them by status, calculates a simple average progress from tasks, and prints the result. This is not merely a partial implementation detail; the actual behavior is materially narrower and does not substantiate the broad declared purpose. Therefore, the description does not accurately represent what this code chunk actually does.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
声明描述的是一个功能完整的项目管理工具,涵盖管理、跟踪、报告、提醒、看板等多项核心能力;但提供的代码片段只是一个只读查看脚本,读取本地JSON文件并输出摘要信息。虽然它确实涉及项目详情、部门、里程碑、任务和KPI的展示,与声明中的部分领域对象相关,但其实际行为远不足以支撑“全流程项目管理工具”的主要用途。该代码没有生成报告、发送邮件、创建看板、管理排期、更新数据或执行预警,因此描述明显夸大了该代码块的能力,构成实质性不匹配。

Lp3

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding
The skill advertises and documents file read/write behavior via local project JSON files, report outputs, boards, and backups, but it does not declare any explicit tool scope such as allowed-tools or permissions. Missing scope declarations weaken least-privilege controls and make it harder for users or hosting platforms to understand and constrain filesystem access before use.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The skill describes sending reminder emails, which may transmit project names, deadlines, assignees, blockers, or other internal business data through SMTP or external mail infrastructure, yet it provides no privacy, classification, or data-handling warning. In a project-management context, this can expose sensitive operational information to unintended recipients or third-party providers if misconfigured or used with confidential projects.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The skill documents persistent writes of project data, reports, boards, and exports to local files without warning about retention, overwrite, path safety, or privacy implications. In this context, project records may contain personnel assignments, schedules, KPIs, and internal status notes, so silent persistence increases the risk of unauthorized local disclosure, accidental commit to source control, or destructive overwrites.

Natural-Language Policy Violations

Medium
Confidence
97% confidence
Finding
The docstrings, CLI description/help text, warnings, and success messages are all hard-coded in Chinese throughout the script. This imposes a specific language on users without opt-in or any documented locale constraint, which matches the natural-language policy violation criteria.

Natural-Language Policy Violations

Medium
Confidence
97% confidence
Finding
The module docstring and CLI usage text are written only in Chinese, and the interactive prompts and status output later in the file also assume Chinese-speaking users. This is a natural-language policy concern because the script imposes a specific language without any user opt-in or documented regional justification.

Natural-Language Policy Violations

Medium
Confidence
98% confidence
Finding
This code file includes user-facing documentation and output strings only in Chinese, including the module docstring and CLI help context. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation unless the locale restriction is explicitly justified, which is not present here.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The file’s user-facing documentation and descriptions are entirely in Chinese, including the purpose and usage text. This imposes a specific language/locale on users without offering a choice or documenting that the skill is intended only for a Chinese-speaking or region-specific context.

Intent-Code Divergence

Medium
Confidence
98% confidence
Finding
The module docstring says '发送任务提醒邮件' and provides usage implying email sending, while the implementation only writes email content to an `emails/*.txt` file and prints instructions to send it manually. This is an intent-level contradiction because the documented primary action is sending, but the actual behavior is draft generation only.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
This code file contains natural-language instructions and output entirely in Chinese, beginning with the module docstring and continuing throughout CLI help and status messages. Under the policy rule, forcing a specific language without user opt-in is a locale/language policy violation unless the constraint is explicitly documented and justified, which it is not here.

Intent-Code Divergence

Medium
Confidence
96% confidence
Finding
The function name `send_reminder` and docstring '生成提醒邮件内容' are paired with a CLI parser description '发送任务提醒', suggesting an email-sending operation. However, the code's side effect is limited to creating a local text file in the `emails` directory, as confirmed by the '保存邮件草稿' comment and manual-send instructions.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
The module docstring, argparse help text, and printed status messages are all written exclusively in Chinese, which imposes a specific language on users. There is no opt-in, alternative locale, or documented reason that this skill is intentionally region-specific, so this is a natural-language policy violation under the language/locale rule.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The file’s docstrings and all user-facing output strings are hard-coded in Chinese, which imposes a specific language on users without any opt-in or selection mechanism. This matches the language/locale policy violation category because the skill does not offer an alternative language or document a justified locale restriction.

Natural-Language Policy Violations

Low
Confidence
95% confidence
Finding
The file's user-facing text, help output, and allowed status values are all hard-coded in Chinese, including the docstring, argparse descriptions, and printed messages. For a general-purpose CLI skill, this imposes a specific language/locale without user opt-in, which matches the natural-language policy violation criteria.

Natural-Language Policy Violations

Low
Confidence
96% confidence
Finding
This is a natural-language policy issue because the file hardcodes its usage and descriptive strings in a single language. Users who do not read Chinese are not given an opt-in, fallback, or explanation that the skill is intended only for a Chinese-speaking context.

Static analysis

No suspicious patterns detected.