Back to skill

Security audit

tapd-api

Security checks for vulnerabilities and agentic risk

Overview

This is a TAPD API integration, but it caches live OAuth tokens insecurely and includes examples that can change shared project data without strong safeguards.

Install only if you are comfortable giving this skill TAPD read/write access for the configured workspaces. Use least-privilege TAPD credentials, test in a non-production workspace first, avoid running bulk update examples without review, and protect or disable the token cache where possible.

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

Warning
Location
scripts/tapd_client.py:59
Finding
OAuth Bearer Token Cached Without Restrictive File Permissions<![CDATA[ ## Vulnerability Details **File Location**: `scripts/tapd_client.py:59-68` **Vulnerability Type**: Plaintext credential storage with insufficient access controls **Risk Level**: Medium ### Vulnerable Code ```python def _save_token_cache(self): """保存 OAuth token 到缓存""" cache = { "access_token": self._access_token, "expires_at": self._token_expires_at, "updated_at": time.time() } with open(self.TOKEN_CACHE_FILE, "w") as f: json.dump(cache, f) ``` ### Technical Analysis The client stores a live OAuth bearer token in plaintext at the predictable path `~/.tapd_token_cache.json`. The file is opened using the standard `open(..., "w")` operation without explicitly enforcing owner-only permissions. For a newly created file, its permissions depend on the process umask. With a permissive umask, the cache may be readable by other local users. If the file already exists with overly broad permissions, opening it for writing does not correct those permissions. The implementation also does not validate whether the destination is a regular file owned by the current user or an unexpected symbolic link. A bearer token is sufficient to authenticate requests without knowledge of the OAuth client secret. Consequently, anyone who obtains the cached token can replay it until it expires. The network transmission itself is necessary for the declared TAPD integration and is restricted to `https://api.tapd.cn`; the vulnerability is the insecure local storage of the resulting credential. ### Attack Path 1. A legitimate user runs the TAPD client with valid OAuth credentials. 2. The client requests an access token from TAPD. 3. `_save_token_cache()` writes the bearer token to `~/.tapd_token_cache.json`. 4. The file is created under a permissive umask or retains previously insecure permissions. 5. Another local user or compromised process reads the cache file. 6. The attacker extracts the `access_token` value. 7. The attacker ...[truncated 886 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Atomically create the token cache with owner-only mode `0600`, rather than relying on the process umask. - Correct the permissions of an existing cache before reading or writing it. - Validate that the target is a regular file owned by the current user and reject unexpected symbolic links. - Write through a securely created temporary file in the same directory, flush it, and atomically replace the destination. - Consider making persistent token caching opt-in or allowing users to disable it entirely. - Delete expired tokens and provide an explicit command to clear the cache. - Avoid storing the token if a platform credential manager or operating-system keyring is available. Example hardening approach: ```python import os import stat flags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC if hasattr(os, "O_NOFOLLOW"): flags |= os.O_NOFOLLOW fd = os.open(self.TOKEN_CACHE_FILE, flags, 0o600) try: os.fchmod(fd, stat.S_IRUSR | stat.S_IWUSR) with os.fdopen(fd, "w") as f: fd = -1 json.dump(cache, f) finally: if fd != -1: os.close(fd) ``` Additional ownership and regular-file checks should be applied before trusting an existing cache. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
reference/examples.md:194
Finding
Documentation Encourages Disclosure of OAuth Token Material<![CDATA[ ## Vulnerability Details **File Location**: `reference/examples.md:194-205` **Vulnerability Type**: Sensitive credential exposure through terminal or log output **Risk Level**: Low ### Vulnerable Code ```python # Token 自动缓存到 ~/.tapd_token_cache.json # 2 小时内不会重复请求 # 查看缓存 import json with open("~/.tapd_token_cache.json") as f: cache = json.load(f) print(f"Token: {cache['access_token'][:20]}...") print(f"过期时间: {cache['expires_at']}") ``` ### Technical Analysis The example instructs users to read the OAuth cache and print the first 20 characters of a bearer token. Authentication tokens should be treated as opaque secrets and should not be emitted to terminals, logs, CI output, support transcripts, screen recordings, or shared command histories. Although the example does not print the entire token, partial token disclosure may reveal token format or identifying material and encourages unsafe operational handling. Future edits or user adaptations may also remove the slicing and expose the complete token. The example additionally uses the literal path `"~/.tapd_token_cache.json"`. Python's `open()` does not expand `~`, so the example is functionally incorrect unless a directory literally named `~` exists in the current working directory. This path issue is not itself a security vulnerability, but it may prompt users to copy the sensitive cache to less protected locations while troubleshooting. ### Attack Path 1. A user follows or adapts the documented token-cache inspection example. 2. Token material is printed to a terminal, notebook, CI job, diagnostic log, or recorded support session. 3. An unauthorized person obtains access to that output. 4. If the complete token was printed by an adapted version, the observer replays it directly against TAPD. 5. If only the documented prefix is disclosed, the observer gains sensitive identifying information and may correlate it with other leaked token fragments or use it to verify possession of rel ...[truncated 601 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Remove all output of token content, including prefixes. - Display only non-secret metadata such as the expiration timestamp or whether a cached token exists. - Use a fixed redacted marker if token status must be shown. - Use `Path.home()` or `os.path.expanduser()` when documenting the cache path. - Warn users not to include cache contents in logs, screenshots, bug reports, or support messages. A safer example is: ```python import json from pathlib import Path cache_path = Path.home() / ".tapd_token_cache.json" with cache_path.open() as f: cache = json.load(f) print("Token: [REDACTED]") print(f"Expires at: {cache['expires_at']}") ``` ]]>
Vulnerability Patterns
  • 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
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
Findings (33)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
从行为上看,这段代码的主目的确实是 TAPD API 客户端,不存在明显的额外恶意或无关能力;它访问的资源也与声明一致,仅与 TAPD API 通信并在本地缓存 token。但声明中的“完整集成”“实现所有 API 模块和方法”“涵盖所有 TAPD 功能”明显夸大。代码虽然实现了不少模块和接口封装,但远不能从该片段证明是全量覆盖;而且模块数量与声明的 18 个并不吻合。更重要的是,_load_oauth_config 函数没有实际从配置文件读取 client_id/client_secret,却直接访问未初始化属性 self.client_id/self.client_secret,并引用 self.workspaces 等未定义内容,说明其宣称的完整 OAuth 配置支持并未真正实现。因此应判定为描述与实际行为存在实质性不匹配,属于过度声明功能范围。

External Script Fetching

High
Category
Supply Chain
Content
CLIENT_SECRET="your-client-secret"

# 获取 access_token
ACCESS_TOKEN=$(curl -s -u "$CLIENT_ID:$CLIENT_SECRET" \
  -d "grant_type=client_credentials" \
  "https://api.tapd.cn/tokens/request_token" \
  | python3 -c "import json, sys; print(json.load(sys.stdin)['data']['access_token'])")
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Intent-Code Divergence

High
Confidence
98% confidence
Finding
L734 的 docstring 明确说明该函数会“从 tapd.json 加载 OAuth 配置”,且 L735-L736 还构造了默认配置文件路径,但后续实现没有任何文件读取或解析逻辑。相反,L738 直接检查 self.client_id 和 self.client_secret,这与文档描述的“加载配置”行为相矛盾,属于主动性的意图-代码背离。

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
该技能说明从开头即以中文描述全部功能,且全文未提供语言切换、用户选择或适用地区范围说明。根据规则,若技能强制特定语言而无用户 opt-in 或明确合理的区域性约束,属于自然语言政策违规。

Session Persistence

Medium
Category
Rogue Agent
Content
./scripts/tapd-api.sh story list --status planning --limit 50

# 创建需求(需要修改脚本支持更多参数)
python3 scripts/tapd_client.py story create \
  --workspace 12345678 \
  --name "新需求标题"
```
Confidence
60% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Natural-Language Policy Violations

Medium
Confidence
90% confidence
Finding
This markdown file contains all user-facing instructions in Chinese and does not indicate that the skill is China-specific or that users may choose another language. Under the policy rule, forcing a specific language without opt-in is a natural-language policy violation.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
**安全设置**:
```bash
chmod 600 tapd.json
```

### 备选方式:环境变量
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
**安全设置**:
```bash
chmod 600 tapd.json
```

### 备选方式:环境变量
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
**安全设置**:
```bash
chmod 600 tapd.json
```

### 备选方式:环境变量
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
**安全设置**:
```bash
chmod 600 tapd.json
```

### 备选方式:环境变量
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
**安全设置**:
```bash
chmod 600 tapd.json
```

### 备选方式:环境变量
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
1. **使用** tapd.json 或环境变量存储真实配置
2. **添加** tapd.json 到 .gitignore
3. **设置**文件权限 `chmod 600 tapd.json`
4. **避免**硬编码凭证到代码中
5. **定期**轮换 OAuth 密钥
6. **启用** IP 白名单(在 TAPD 开放平台)
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
1. **使用** tapd.json 或环境变量存储真实配置
2. **添加** tapd.json 到 .gitignore
3. **设置**文件权限 `chmod 600 tapd.json`
4. **避免**硬编码凭证到代码中
5. **定期**轮换 OAuth 密钥
6. **启用** IP 白名单(在 TAPD 开放平台)
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill documents capabilities that read/write local files and make outbound network requests, but it declares no explicit tool scope or permissions. In an agent setting, this weakens user visibility and policy enforcement, increasing the chance that the skill accesses secrets or transmits project data without clear consent boundaries.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The documentation shows credentialed OAuth exchanges and API calls but does not clearly warn that client secrets, bearer tokens, and project data are transmitted to TAPD servers. In a skill ecosystem, users may treat examples as local-only operations and unintentionally expose sensitive credentials or business data to external services.

External Transmission

Medium
Category
Data Exfiltration
Content
CLIENT_SECRET="your-client-secret"

# 获取 access_token
ACCESS_TOKEN=$(curl -s -u "$CLIENT_ID:$CLIENT_SECRET" \
  -d "grant_type=client_credentials" \
  "https://api.tapd.cn/tokens/request_token" \
  | python3 -c "import json, sys; print(json.load(sys.stdin)['data']['access_token'])")
Confidence
93% confidence
Finding
This example transmits OAuth client credentials to an external TAPD endpoint to obtain an access token. The network transmission is expected for the integration, but in a skill context it is security-relevant because it handles sensitive secrets and can expose them through logs, shell history, or misuse if users do not understand the outbound behavior.

External Transmission

Medium
Category
Data Exfiltration
Content
# 获取 access_token
ACCESS_TOKEN=$(curl -s -u "$CLIENT_ID:$CLIENT_SECRET" \
  -d "grant_type=client_credentials" \
  "https://api.tapd.cn/tokens/request_token" \
  | python3 -c "import json, sys; print(json.load(sys.stdin)['data']['access_token'])")

# 调用 API
Confidence
89% confidence
Finding
The skill communicates with an external TAPD domain, which means user data and authentication artifacts leave the local environment. That is normal for an API client, but it is still a real security concern when the skill does not pair the example with strong disclosures and scoped permissions.

External Transmission

Medium
Category
Data Exfiltration
Content
# 调用 API
curl -H "Authorization: Bearer $ACCESS_TOKEN" \
  "https://api.tapd.cn/stories?workspace_id=12345678&limit=10"
```

## 🔌 API 端点
Confidence
89% confidence
Finding
This API call sends a bearer token and workspace-scoped query to TAPD, exposing project metadata and potentially sensitive records to a remote service. The behavior is integral to the skill, but it should still be treated as a genuine external-transmission risk requiring clear consent and least-privilege controls.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The skill documents create and update operations against remote TAPD objects without a strong warning that these commands will modify production project data. In practice, users may run examples assuming they are harmless demos, causing unintended changes to requirements, tasks, or bugs.

External Transmission

Medium
Category
Data Exfiltration
Content
```bash
curl -H "Authorization: Bearer ACCESS_TOKEN" \
  "https://api.tapd.cn/workspaces/projects"
```

返回:
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
These examples demonstrate creation of new stories and status-changing updates on remote TAPD records without telling users they will modify production project data. Because this is an agent skill intended for automation, omission of side-effect warnings makes accidental execution more likely and can lead to unauthorized or mistaken changes in shared workspaces.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The bulk update example performs repeated write operations against live TAPD records without any warning, confirmation step, dry-run mode, or sandbox guidance. In an automation/agent setting, users may run examples verbatim, causing unintended mass state changes to project data and workflow disruption.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The token cache section discusses direct cache inspection and credential handling without warning that the file contains live OAuth secrets. In practice, readers may expose tokens through console output, screenshots, shell history, or copied snippets, which can enable unauthorized TAPD API access if the token is reused before expiry.

Context-Inappropriate Capability

Medium
Confidence
97% confidence
Finding
The example explicitly instructs users to open the local token cache and print part of the access token, normalizing direct handling and display of sensitive credentials. In an agent skill context, this is dangerous because example code is often copied into terminals, logs, notebooks, or chat transcripts, increasing the chance that TAPD OAuth tokens are exposed beyond their intended scope.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The client persists the OAuth access token to a predictable file in the user's home directory without setting restrictive file permissions or giving the user control over secure storage. If the host is multi-user, backed up, synced, or otherwise exposed, a stolen token could allow unauthorized TAPD API access until expiry and possibly facilitate further project data access.

Static analysis

No suspicious patterns detected.