Back to skill

Security audit

Competition Assistant

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly coherent, but it persistently stores raw contact details and its helper script can expose complete personal records despite the skill promising masked contact output.

Review this skill before installing. It is not showing evidence of malware, but users should not enter real phone, email, QQ, or WeChat details unless they accept persistent local storage and possible raw-record exposure through the helper script. The publisher should add explicit consent, retention and deletion controls, restrictive file permissions, and ensure list/match outputs never include raw contact fields.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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 (2)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/teaming-manager.py:18
Finding
Plaintext Storage of Raw Personal Contact Information<![CDATA[ ## Vulnerability Details **File Location**: `scripts/teaming-manager.py`, lines 18, 36–39, and 103–104 **Vulnerability Type**: Plaintext sensitive-data storage with insufficient file-permission enforcement **Risk Level**: High ### Vulnerable Code ```python DATA_FILE = Path.home() / ".openclaw" / "workspace" / "memory" / "teaming-requests.json" ``` ```python def save_data(data: dict): """保存数据""" data["lastUpdated"] = datetime.now().isoformat() with open(DATA_FILE, 'w', encoding='utf-8') as f: json.dump(data, f, ensure_ascii=False, indent=2) ``` ```python "contact": contact, "contactMasked": mask_contact(contact), ``` ### Technical Analysis The teaming feature stores both the masked contact value and the original contact value in a predictable JSON file under the user's home directory. The original value may contain a phone number, email address, QQ identifier, WeChat identifier, or another personal contact credential. Although the application generates a masked representation, retaining the raw value defeats data minimization. The implementation also opens the file without explicitly enforcing restrictive permissions. Consequently, the resulting access permissions depend on the process environment and its `umask`. The raw contact value is not necessary for the documented matching calculation. Matching uses competition names, skills, and availability, while output is explicitly supposed to use the masked value. Therefore, retaining raw contact information exceeds the minimum data privileges needed for the declared functionality. ### Attack Path 1. A user submits a teaming request containing a phone number, email address, QQ ID, or WeChat ID. 2. `add_request()` inserts both `contact` and `contactMasked` into the request object. 3. `save_data()` serializes the complete object to the predictable path `~/.openclaw/workspace/memory/teaming-requests.json`. 4. A local user, process, plugin, backup service, or other ...[truncated 690 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not persist the original `contact` value unless there is a documented functional requirement for it. Store only `contactMasked` where possible. 2. If later disclosure of the original contact is necessary, encrypt it using authenticated encryption and keep encryption keys outside the data file. 3. Create the storage file with owner-only permissions such as `0600`, and ensure the parent directory is accessible only by the owning account. 4. Write updates atomically through a securely created temporary file, apply restrictive permissions, and then replace the destination. 5. Introduce a retention policy that removes expired, closed, or abandoned requests and their associated contact data. 6. Validate that backups, diagnostic output, and logs cannot capture the raw contact value. 7. Document user consent, storage duration, deletion controls, and the purpose for which contact information is retained. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/teaming-manager.py:118
Finding
Unauthenticated Enumeration and Disclosure of Complete Teaming Records<![CDATA[ ## Vulnerability Details **File Location**: `scripts/teaming-manager.py`, lines 118–132, 175–203, and 220–228 **Vulnerability Type**: Missing authorization and excessive sensitive-data exposure **Risk Level**: High ### Vulnerable Code ```python def list_requests(status: str = "active", competition: str = None) -> list: """列出组队需求""" data = load_data() requests = data.get("requests", []) # 过滤状态 if status: requests = [r for r in requests if r.get("status") == status] # 过滤比赛 if competition: requests = [r for r in requests if competition in r.get("competition", {}).get("name", "")] # 过滤过期 today = datetime.now().date() requests = [r for r in requests if datetime.strptime(r.get("deadline", "2099-12-31"), "%Y-%m-%d").date() >= today] return requests ``` ```python def find_matches(user_id: str, competition: str = None, limit: int = 2) -> list: """为用户寻找匹配的队友""" data = load_data() requests = data.get("requests", []) # 找到用户自己的需求 user_requests = [r for r in requests if r.get("userId") == user_id and r.get("status") == "active"] if not user_requests: return [] user_req = user_requests[0] # 找其他人的需求 other_requests = [r for r in requests if r.get("userId") != user_id and r.get("status") == "active"] # 计算匹配分数 matches = [] for other in other_requests: score = calculate_match_score(user_req, other) if score >= 30: matches.append({ "request": other, "score": score }) # 排序并返回前N个 matches.sort(key=lambda x: (-x["score"], x["request"]["createdAt"])) return matches[:limit] ``` ```python if cmd == "list": reqs = list_requests() print(json.dumps(reqs, ensure_ascii=False, indent=2)) elif cmd == "match": if len(sys.argv) < 3: print("用法: teaming-manager.py match <user_id>") sys. ...[truncated 2469 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace complete-object returns with an explicit public projection containing only required fields, such as competition name, relevant skills, availability summary, score, and `contactMasked`. 2. Never include the raw `contact` field in list, match, logging, or CLI output. 3. Require a trusted caller identity rather than accepting an unauthenticated user ID as proof of ownership. 4. Enforce record-level authorization before reading, matching, updating, or deleting a user's request. 5. Remove the unrestricted global `list` operation or restrict it to an explicitly authorized administrative context. 6. Separate internal storage models from public response models so newly added sensitive fields are not automatically exposed. 7. Add automated tests asserting that serialized output never contains `contact` and that one user cannot query another user's private record by supplying a different identifier. 8. Consider providing a consent-based contact exchange mechanism instead of exposing even masked identifiers before both parties approve a match. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (12)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The declared behavior and the actual described operations do not fully align: the skill promises real-time competition calendar functionality while also persisting team requests and raw contact data locally. Behavior mismatches are dangerous because users and reviewers may not understand the real data handling, leading to unanticipated retention of sensitive information.

YARA rule 'agent_skill_mcp_tool_poisoning_metadata': MCP/tool metadata poisoning indicators in tool schemas or skill manifests [agent_skills]

High
Category
YARA Match
Content
---
name: competition-assistant
description: 大学生竞赛助手 — 提供赛事月历生成与组队匹配服务。触发场景:(1) 用户询问比赛信息、赛事日程、近期竞赛、"汇总比赛"、"赛事月历"、"有哪些比赛"等;(2) 用户需要组队找队友、"匹配比赛队伍"、"找队友"、"帮我匹配"、描述组队需求如"我想找互联网+的队友"或"有没有人在做挑战杯缺人"。功能包括:实时获取教育部认可84项学科竞赛的报名时间、比赛时间;跨会话持久化的组队需求管理与智能匹配推荐。
---

# 大学生竞赛助手

我已经准�
Confidence
80% confidence
Finding
YARA rule matched a hack tool or exploit indicator (offensive tools, reconnaissance, privilege escalation, or exploit frameworks).

Missing User Warnings

High
Confidence
97% confidence
Finding
The skill states that contact details will be stored across sessions, but it does not present a clear user warning, consent flow, retention policy, or sharing notice. Because the data is personally identifying and intended for later matching/disclosure, missing explicit informed consent materially raises privacy and compliance risk.

Lp3

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding
The skill describes capabilities that imply file read/write and network access, but it does not declare any explicit tool scope or permission boundaries. This increases the chance of over-broad execution in an agent runtime and makes it harder to audit or constrain what the skill is allowed to access.

Vague Triggers

Medium
Confidence
93% confidence
Finding
The trigger phrases for team matching are broad enough to overlap with ordinary conversational requests, which can cause the skill to activate unexpectedly and begin collecting sensitive details like contact information. In this context, accidental activation is more dangerous because the skill performs cross-session persistence and later disclosure to other users.

Ssd 3

Medium
Confidence
97% confidence
Finding
The skill collects users' contact details, stores them persistently across sessions, and uses them for later matching and disclosure to other users. Even with masking on display, storing original contact values creates a sensitive data repository that could be exposed, misused, or retained longer than users expect.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
This markdown file contains all user-facing instructions and schema descriptions in Chinese, and nowhere indicates that the skill is China-specific or that users may choose another language. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The code stores user identifiers, names, free-time details, notes, and full contact information in a persistent file under the user's home directory without any visible consent, retention policy, or disclosure mechanism. For a cross-session matching tool, silent persistence of personal data raises privacy and compliance concerns and can surprise users who do not expect long-term storage.

Description-Behavior Mismatch

Medium
Confidence
94% confidence
Finding
The script persists full contact details in the request object and returns whole request records from list and match flows, so any caller of those functions can access unmasked personal contact data. In a team-matching assistant, this creates unnecessary exposure of sensitive personal information beyond the minimum needed for recommendation, increasing privacy and abuse risk.

Natural-Language Policy Violations

Low
Confidence
84% confidence
Finding
This markdown file is entirely written in Chinese and provides no indication that users may choose another language or locale. Under the natural-language policy rule, a skill artifact that effectively enforces a specific language without opt-in can be considered a locale-policy violation.

Natural-Language Policy Violations

Low
Confidence
88% confidence
Finding
The natural-language docstrings and CLI messages are written only in Chinese, with no indication that users may choose another language or locale. Under the policy, forcing a specific language without opt-in can be a natural-language policy violation unless clearly justified.

Description-Behavior Mismatch

Low
Confidence
72% confidence
Finding
The manifest focuses on creating persistent teaming needs and recommending matches, but the code also implements mutation operations to change status and delete records. Those lifecycle-management capabilities may be reasonable implementation choices, but they are not described in the stated functionality.

Static analysis

No suspicious patterns detected.