Back to skill

Security audit

禅道-ZenTao

Security checks for vulnerabilities and agentic risk

Overview

This ZenTao integration is mostly purpose-aligned, but it handles credentials and project-management mutations with enough insecure transport and scoping risk that users should review it carefully before installing.

Install only if you understand that this skill will use credentials from TOOLS.md to access your ZenTao server and may perform high-impact changes with your account's permissions. Use an HTTPS-only ZenTao URL, prefer a least-privilege service account, avoid committing TOOLS.md, and require explicit confirmation before any create, update, delete, review, or test-run action.

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
lib/zentao_client.py:34
Finding
ZenTao credentials can be transmitted over plaintext HTTP<![CDATA[ ## Vulnerability Details **File Location**: `lib/zentao_client.py:34-39`; equivalent behavior in `lib/zentao_rest_client.py:25-31`; insecure HTTP examples in `SKILL.md:52-60`, `SKILL.md:312-320`, and `package.json:18` **Vulnerability Type**: Cleartext transmission of sensitive authentication information **Risk Level**: High ### Vulnerable Code ```python def get_token(self) -> Optional[str]: """REST API: Get Token""" try: url = f"{self.rest_api_base}/tokens" data = {'account': self.username, 'password': self.password} response = httpx.post(url, json=data, timeout=30) ``` The REST client contains the equivalent implementation: ```python def get_token(self) -> Optional[str]: """POST /tokens - Get Token""" url = f"{self.base_url}/tokens" data = {'account': self.username, 'password': self.password} try: response = httpx.post(url, json=data, timeout=30) ``` The documented configuration explicitly recommends an HTTP URL: ```markdown - **API URL:** http://<your-zentao-host>/ - **Username:** <your-username> - **Password:** <your-password> ``` ### Technical Analysis The endpoint is read from the credential configuration and used without validating its scheme. Both API clients submit the ZenTao username and password directly to the resulting `/tokens` endpoint. The legacy authentication implementation also submits the password to the configured endpoint. If the endpoint begins with `http://`, neither `httpx` nor `requests` provides transport encryption. The password, username, session identifiers, authentication token, API requests, and returned project-management data can consequently be observed or modified by any attacker able to intercept the connection. This behavior is directly encouraged by the examples in `SKILL.md` and `package.json`. Network communication is necessary for the declared ZenTao integration, but supporting plaintext credential transport without a warning or explicit opt-in ...[truncated 1430 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Require `https://` endpoints by default and reject `http://` before any credentials are transmitted. 2. If plaintext HTTP is required for isolated development environments, require a conspicuous and explicit opt-in such as `allow_insecure_http=True`; keep it disabled by default. 3. Replace all HTTP examples in `SKILL.md`, `package.json`, and CLI help text with HTTPS examples. 4. Validate endpoints with a URL parser and permit only the expected `http` or `https` schemes; reject embedded user information, fragments, and malformed URLs. 5. Preserve TLS certificate verification and document how users should configure a trusted internal certificate authority. 6. Recommend a dedicated ZenTao service account with only the permissions required for the intended operations. 7. Consider warning users before authenticating to a newly configured host, displaying only a sanitized hostname and scheme. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
lib/zentao_rest_client.py:482
Finding
Authentication tokens and session identifiers can leak through output and URLs<![CDATA[ ## Vulnerability Details **File Location**: `lib/zentao_rest_client.py:482-490`; related session exposure in `lib/zentao_client.py:52-73` and `lib/zentao_client.py:111-120` **Vulnerability Type**: Sensitive authentication material exposure **Risk Level**: Medium ### Vulnerable Code The REST client's executable test path prints part of the authentication token: ```python if __name__ == '__main__': # Test REST API creds = read_credentials() if creds: client = ZenTaoRESTClient(creds['endpoint'], creds['username'], creds['password']) print("=== REST API Test ===") # Test obtaining Token token = client.get_token() print(f"Token: {token[:20] if token else None}...") ``` The legacy client places its session identifier in request URLs: ```python login_url = f"{self.old_api_base}/user-login.json?zentaosid={self.sid}" self.session = requests.session() login_data = { 'account': self.username, 'password': self.password, 'keepLogin[]': 'on', 'referer': f"{self.old_api_base}/my/" } login_response = self.session.post(login_url, data=login_data, timeout=30) ``` ```python url = f"{self.old_api_base}/{path.lstrip('/')}" if '?' in url: url += f"&zentaosid={self.sid}" else: url += f"?zentaosid={self.sid}" ``` ### Technical Analysis Authentication tokens and session identifiers are bearer-style secrets and must be protected from disclosure. The REST client prints the first 20 characters of the acquired token when the module is run directly. Even partial token disclosure unnecessarily reduces token secrecy and can expose a usable token if a deployment uses short or structured tokens. The legacy API client appends `zentaosid` to every request URL. Sensitive query parameters are routinely recorded by reverse proxies, web servers, monitoring systems, browser or HTTP debugging tools, exception telemetry, and access logs. Anyone with access to those records may obtain the complete session ide ...[truncated 1423 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove all token output, including partial token output, from executable examples and test code. 2. Redact passwords, tokens, session IDs, and authentication headers in application, HTTP-client, proxy, and exception logs. 3. Prefer a secure, `HttpOnly`, `Secure`, and appropriately scoped session cookie or an authorization header instead of a URL query parameter when supported by ZenTao. 4. If the legacy API requires `zentaosid` in the URL, prevent request-target logging or configure all logging layers to redact that parameter. 5. Use HTTPS exclusively so query strings and headers are encrypted in transit. 6. Use short-lived sessions and tokens, rotate them after suspected exposure, and invalidate sessions on logout or authentication failure. 7. Avoid returning raw response bodies in errors where they may contain authentication or sensitive application information. ]]>

T08 · Insecure Dependencies

Note
Location
requirements.txt:4
Finding
Dependency manifests are incomplete and use unbounded version ranges<![CDATA[ ## Vulnerability Details **File Location**: `requirements.txt:4-5`; related metadata in `package.json:7-10`; undocumented import in `lib/zentao_client.py:9-10` and `lib/zentao_rest_client.py:8` **Vulnerability Type**: Non-reproducible and incomplete dependency management **Risk Level**: Low ### Vulnerable Code The Python dependencies are specified only with open-ended minimum versions: ```text requests>=2.28.0 beautifulsoup4>=4.11.0 ``` The package metadata similarly omits exact versions: ```json "dependencies": { "python": ">=3.8", "packages": ["requests", "beautifulsoup4"] } ``` However, both clients import `httpx`, which is not declared: ```python import requests import httpx ``` ```python import httpx ``` ### Technical Analysis Open-ended dependency constraints allow installations at different times to resolve materially different package versions, including future releases that have not been reviewed with this Skill. No lock file or package hashes are present to verify the exact artifacts installed. The required `httpx` package is absent from both dependency declarations. A standard installation can therefore fail at import time. Users may respond by manually installing an arbitrary version from the package index, further reducing reproducibility and bypassing any intended dependency review. `beautifulsoup4` appears in the manifests but was not observed in the reviewed source imports, which unnecessarily increases dependency surface if it is installed solely for this package. ### Attack Path 1. A user installs the Skill dependencies using `pip install -r requirements.txt`. 2. The resolver selects the newest releases satisfying the open-ended constraints rather than a reviewed dependency set. 3. The application fails because `httpx` is missing, prompting the user or automation to install an unspecified version manually. 4. A compromised, vulnerable, or unexpectedly incompatible future release is installed and imported into the Sk ...[truncated 894 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Add `httpx` explicitly to every authoritative dependency manifest. 2. Remove `beautifulsoup4` if it is not required by any executed code. 3. Pin dependencies to reviewed versions, preferably through a generated lock file. 4. Use hashes for distributed Python requirements, such as `pip --require-hashes`, to verify downloaded artifacts. 5. Keep direct requirements and transitive lock data separate so security updates can be reviewed and applied deliberately. 6. Add automated installation and import tests in a clean environment to ensure all runtime dependencies are declared. 7. Use an approved package index and routinely scan the locked dependency set for known vulnerabilities. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (30)

Tool Parameter Abuse

High
Category
Tool Misuse
Content
return self._request('PUT', f'/users/{user_id}', data=data)
    
    def delete_user(self, user_id: int) -> Tuple[bool, Any]:
        """DELETE /users/{id} - 删除用户"""
        return self._request('DELETE', f'/users/{user_id}')
    
    # ==================== 项目集 Program ====================
Confidence
90% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
return self._request('PUT', f'/programs/{program_id}', data=data)
    
    def delete_program(self, program_id: int) -> Tuple[bool, Any]:
        """DELETE /programs/{id} - 删除项目集"""
        return self._request('DELETE', f'/programs/{program_id}')
    
    # ==================== 产品 Product ====================
Confidence
90% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
return self._request('PUT', f'/products/{product_id}', data=data)
    
    def delete_product(self, product_id: int) -> Tuple[bool, Any]:
        """DELETE /products/{id} - 删除产品"""
        return self._request('DELETE', f'/products/{product_id}')
    
    def get_product_teams(self, product_id: int) -> Tuple[bool, Any]:
Confidence
90% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
return self._request('PUT', f'/products/{product_id}/plans/{plan_id}', data=data)
    
    def delete_product_plan(self, product_id: int, plan_id: int) -> Tuple[bool, Any]:
        """DELETE /products/{id}/plans/{planID} - 删除产品计划"""
        return self._request('DELETE', f'/products/{product_id}/plans/{plan_id}')
    
    # ==================== 发布 Release ====================
Confidence
90% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
return self._request('PUT', f'/products/{product_id}/stories/{story_id}', data=data)
    
    def delete_story(self, product_id: int, story_id: int) -> Tuple[bool, Any]:
        """DELETE /products/{id}/stories/{storyID} - 删除需求"""
        return self._request('DELETE', f'/products/{product_id}/stories/{story_id}')
    
    def activate_story(self, product_id: int, story_id: int) -> Tuple[bool, Any]:
Confidence
90% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
return self._request('PUT', f'/projects/{project_id}', data=data)
    
    def delete_project(self, project_id: int) -> Tuple[bool, Any]:
        """DELETE /projects/{id} - 删除项目"""
        return self._request('DELETE', f'/projects/{project_id}')
    
    # ==================== 版本 Build ====================
Confidence
90% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
return self._request('PUT', f'/builds/{build_id}', data=data)
    
    def delete_build(self, build_id: int) -> Tuple[bool, Any]:
        """DELETE /builds/{id} - 删除版本"""
        return self._request('DELETE', f'/builds/{build_id}')
    
    # ==================== 执行 Execution ====================
Confidence
90% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
return self._request('PUT', f'/executions/{execution_id}', data=data)
    
    def delete_execution(self, execution_id: int) -> Tuple[bool, Any]:
        """DELETE /executions/{id} - 删除执行"""
        return self._request('DELETE', f'/executions/{execution_id}')
    
    # ==================== 任务 Task ====================
Confidence
90% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
return self._request('PUT', f'/tasks/{task_id}', data=data)
    
    def delete_task(self, task_id: int) -> Tuple[bool, Any]:
        """DELETE /tasks/{id} - 删除任务"""
        return self._request('DELETE', f'/tasks/{task_id}')
    
    # ==================== 缺陷 Bug ====================
Confidence
90% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
return self._request('PUT', f'/bugs/{bug_id}', data=data)
    
    def delete_bug(self, bug_id: int) -> Tuple[bool, Any]:
        """DELETE /bugs/{id} - 删除 Bug"""
        return self._request('DELETE', f'/bugs/{bug_id}')
    
    # ==================== 用例 TestCase ====================
Confidence
90% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
return self._request('PUT', f'/testcases/{case_id}', data=data)
    
    def delete_test_case(self, case_id: int) -> Tuple[bool, Any]:
        """DELETE /testcases/{id} - 删除用例"""
        return self._request('DELETE', f'/testcases/{case_id}')
    
    # ==================== 测试单 TestTask ====================
Confidence
90% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
return self._request('PUT', f'/feedbacks/{feedback_id}', data=data)
    
    def delete_feedback(self, feedback_id: int) -> Tuple[bool, Any]:
        """DELETE /feedbacks/{id} - 删除反馈"""
        return self._request('DELETE', f'/feedbacks/{feedback_id}')
    
    # ==================== 工单 Ticket ====================
Confidence
90% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
return self._request('PUT', f'/tickets/{ticket_id}', data=data)
    
    def delete_ticket(self, ticket_id: int) -> Tuple[bool, Any]:
        """DELETE /tickets/{id} - 删除工单"""
        return self._request('DELETE', f'/tickets/{ticket_id}')
Confidence
90% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Vague Triggers

Medium
Confidence
94% confidence
Finding
The trigger list includes generic terms such as 'project management' and broad product names that can overlap with ordinary user requests, causing the skill to activate in contexts where the user did not clearly intend to use this integration. Because the skill reads credentials and can access organizational project data, overbroad activation increases the chance of unintended data exposure or execution of sensitive queries.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
### Features

#### Query Operations (No Confirmation Required)

**User**
- Get user list
Confidence
87% confidence
Finding
The skill explicitly allows many query operations with no confirmation, including user, product, project, task, and bug retrieval. In a credentialed enterprise integration, that creates an autonomous data-access path where ambiguous or accidental invocation could disclose potentially sensitive organizational metadata without a deliberate confirmation step.

Tainted flow: 'data' from requests.get (line 259, network input) → httpx.post (network output)

Medium
Category
Data Flow
Content
if method.upper() == 'GET':
                response = httpx.get(url, headers=headers, timeout=30)
            elif method.upper() == 'POST':
                response = httpx.post(url, headers=headers, json=data, timeout=30)
            else:
                return False, f"不支持的方法:{method}"
Confidence
65% confidence
Finding
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Tainted flow: 'data' from requests.get (line 259, network input) → requests.post (network output)

Medium
Category
Data Flow
Content
if method.upper() == 'GET':
                response = requests.get(url, timeout=30)
            elif method.upper() == 'POST':
                response = requests.post(url, data=data, timeout=30)
            else:
                return False, f"不支持的方法:{method}"
Confidence
65% confidence
Finding
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
This client implements multiple write-capable operations against ZenTao, including creating stories, tasks, release plans, approving stories, and running test cases. In a skill context with no declared guardrails, approval workflow, or purpose limitation, these methods enable unauthorized or unintended mutation of project-management data if the skill is invoked with available credentials.

Context-Inappropriate Capability

Medium
Confidence
97% confidence
Finding
The code automatically reads ZenTao endpoint and plaintext credentials from a local TOOLS.md file in the user's workspace, which is a sensitive local secret source unrelated to secure credential handling. In an agent-skill context, this is dangerous because it silently harvests credentials from disk and can then use them to access remote systems without explicit user approval at runtime.

Missing User Warnings

Medium
Confidence
98% confidence
Finding
The function reads credentials from a local TOOLS.md path without any user-facing warning, consent prompt, or disclosure that secrets will be accessed from disk. In an agent environment, undisclosed secret access is a significant trust and privacy violation because users may not expect a skill to inspect local files for reusable credentials.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The get_token method sends the configured username and password to the remote ZenTao API using an HTTP POST request. The file contains no user-facing warning, confirmation, or clear disclosure that local credentials will be transmitted to the configured endpoint.

Context-Inappropriate Capability

Medium
Confidence
92% confidence
Finding
The module automatically reads ZenTao endpoint and credentials from a local TOOLS.md file in the user's workspace, which is a sensitive file access behavior beyond the core necessity of a generic REST client. In an agent/skill context, this enables implicit secret harvesting and use of credentials without explicit user consent at call time, increasing the risk of credential misuse or unexpected data access.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The code reads stored credentials from a local TOOLS.md file without any user-facing disclosure, confirmation, or consent flow. In a skill environment, silently consuming secrets from a user workspace is dangerous because users may not realize the skill is capable of discovering and using credentials automatically.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
This file’s natural-language interface begins by declaring the tool in Chinese, and the rest of the user-facing prompts and help text are likewise fixed to Chinese. That enforces a specific language/locale for all users without any visible option to choose another language, which matches the language/locale policy violation criteria.

Intent-Code Divergence

Medium
Confidence
96% confidence
Finding
The create_task path requires params ['execution_id', 'story_id', 'name', 'assign_to'], but parse_args does not extract a 'name' field and the usage text tells users to supply 标题=xxx instead. This is an active contradiction between the documented CLI intent and the implemented parameter handling, causing the advertised command to fail even when used as shown.

Static analysis

No suspicious patterns detected.