Back to skill

Security audit

Sda Publish Clean

Security checks for vulnerabilities and agentic risk

Overview

This sports-report skill has a coherent main purpose, but it needs Review because it combines automatic execution, network fetching, local file changes, broad triggers, and sensitive avatar/gender heuristics without tight controls.

Install only if you are comfortable with a sports-report skill that can run Python scripts, fetch public sports data, read API keys from environment variables, and write report/data files. Before broad use, disable or restrict the generic --url fetch, require opt-in for daily automation, avoid --write-gender and in-place --fix on authoritative datasets, and review generated reports for promotional sections and sensitive avatar assumptions.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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)

T01 · Skill Instruction Hijacking

Error
Location
scripts/analytics.py:1929
Finding
Mandatory Promotional and Retention Content Hijacks Generated Reports<![CDATA[ ## Vulnerability Details **File Location**: `scripts/analytics.py:1929-1937`, with unconditional insertion at `scripts/analytics.py:2050` **Vulnerability Type**: Mandatory output manipulation and platform-retention promotion **Risk Level**: High ### Vulnerable Code ```python hook_html = ("<div class='hook'>" "<div class='hook-h'>🔥 今日最值得看 · Top %d</div>" "%s" "<div class='hook-chips'>🛡️ 只做信息整理 · 不做赛果判断 | ✅ 对阵已联网核实 | 📤 一键分享发群 / 朋友圈</div>" "</div>") % (len(_top3), _hook_cards) # —— Task1 留存:底部「每日自动推送」订阅引导 —— sub_cta = ("<div class='card subcta'>" "<h2>📅 想要每天都自动收到这份总览?</h2>" "<div class='sc-item'>设置「每日体育赛事」自动化后,智能体会在每天固定时间<b>自动联网核实当日真实赛事</b>并生成这份总览,开赛前自动推送给你——信息全、来得及时,还不用自己动手。</div>" "<div class='pnote'>在 WorkBuddy 中说「每天给我发今日赛事总览」即可一键开启。</div>" "</div>") ``` The promotional components are then inserted unconditionally: ```python html = ("<!doctype html><html lang='zh-CN'><head><meta charset='utf-8'>" ... "</style></head><body><div class='wrap'>" + hero + hook_html + live_banner + banner + anti_scam_html() + guide + focus_note + dash + radar_html + details + share_card_html(matches, "daily") + sub_cta + feedback_html() + foot + ENHANCE_JS + "</div></body></html>") ``` Related instructions also characterize the branding card as fixed and require reports to be presented through the Agent workflow. ### Technical Analysis The report builder always appends platform-retention, social-sharing, branding, and feedback components to the requested sports report. The caller has no parameter for disabling these sections. These components are not necessary for the declared core operation of processing sports data and rendering it as an HTML report. In particular, the fixed call to action directs users to enable recurring WorkBuddy automation, while the sharing component encourages redistribution to groups an ...[truncated 1622 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove promotional and platform-retention components from the default report-generation path. 2. Add explicit, disabled-by-default options such as: - `--include-branding` - `--include-sharing-tools` - `--include-feedback` - `--include-subscription-cta` 3. Generate only the sports information requested by the user unless the user affirmatively opts into additional components. 4. Separate neutral report rendering from marketing or publisher-facing functionality. 5. Do not instruct the Agent to include promotional content as a mandatory part of delivery. 6. Add automated tests verifying that the default report contains no subscription, social-sharing, platform-retention, or promotional calls to action. 7. If attribution is required, use a concise and non-interactive attribution footer rather than a retention or redistribution prompt. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/analytics.py:2134
Finding
Unrestricted Caller-Controlled URL Fetch Enables SSRF and Local Resource Access<![CDATA[ ## Vulnerability Details **File Location**: `scripts/analytics.py:2134-2149`; exposed through `--url` at `scripts/analytics.py:2380` **Vulnerability Type**: Server-Side Request Forgery and unsafe URL handling **Risk Level**: Medium ### Vulnerable Code ```python def _cmd_fetch(a): print("⚠️ 合规提醒:仅可从【官方/已授权/公开】数据源抓取;禁止抓取版权内容、付费墙数据或绕过反爬;" "API Key 必须存于环境变量(如 THESPORTSDB_API_KEY),不得硬编码;遵守目标站 ToS 与限流。" "所有抓取结果须按 tier 分级,未证实信息不可作依据。") if a.url: try: req = urllib.request.Request( a.url, headers={"User-Agent": "Mozilla/5.0 (compat; sports-data-analysis)", "Accept": "application/json"}) with urllib.request.urlopen(req, timeout=15) as resp: data = json.loads(resp.read().decode("utf-8")) keys = list(data.keys())[:20] if isinstance(data, dict) else [] print("✅ 已抓取:%s" % a.url) print(" 返回顶层结构:%s" % (keys if keys else type(data).__name__)) print(" 下一步:将 JSON 中的 近期战绩/阵容/伤停 映射到 match.json 对应字段(form_last5/players)。") except Exception as e: print("❌ 抓取失败:%s" % e) print(" 可能原因:无网络 / URL 不可达 / 需鉴权。请改用下方 WebSearch 清单,或配置带 Key 的合规 API(Key 放环境变量)。") ``` The command-line interface exposes the unchecked value directly: ```python pf.add_argument( "--url", default="", help="可选:已授权的 JSON 数据源 URL(鉴权 Key 走环境变量,勿硬编码)" ) ``` ### Technical Analysis The `--url` argument is passed directly to `urllib.request.Request()` and `urllib.request.urlopen()` without security validation. The implementation does not: - Restrict the scheme to HTTPS. - Allowlist approved sports-data hosts. - Reject loopback, private, link-local, multicast, or reserved IP addresses. - Protect cloud instance metadata addresses. - Revalidate the destination after DNS resolution. - Validate redirect targets. - Block local-resource schemes such as `file:`. - Limit the response body size ...[truncated 2462 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove generic URL fetching if it is not essential to the Skill. 2. If it must remain, allow only `https` URLs. 3. Maintain an explicit allowlist of approved sports-data API hostnames. 4. Resolve the hostname before connecting and reject every resolved address in loopback, private, link-local, multicast, unspecified, and reserved ranges. 5. Apply the same validation to every redirect destination and impose a strict redirect limit. 6. Disable `file:`, `ftp:`, `data:`, and all other non-HTTPS schemes. 7. Protect against DNS rebinding by connecting only to a previously validated address while preserving correct TLS hostname verification. 8. Configure a small maximum response size and stream the response rather than calling an unrestricted `read()`. 9. Require an expected JSON content type and validate the response against a strict schema. 10. Avoid exposing detailed network exceptions to untrusted callers because they can improve internal reconnaissance. 11. Add tests covering loopback addresses, IPv6 loopback, private networks, link-local metadata addresses, encoded IP forms, malicious redirects, DNS rebinding scenarios, local-file URLs, and oversized responses. ]]>
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (11)

Tainted flow: 'req' from os.environ.get (line 2093, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Content
a.url,
                headers={"User-Agent": "Mozilla/5.0 (compat; sports-data-analysis)",
                         "Accept": "application/json"})
            with urllib.request.urlopen(req, timeout=15) as resp:
                data = json.loads(resp.read().decode("utf-8"))
            keys = list(data.keys())[:20] if isinstance(data, dict) else []
            print("✅ 已抓取:%s" % a.url)
Confidence
82% confidence
Finding
The --url path allows the skill to fetch any caller-supplied URL with urllib, enabling arbitrary outbound requests. In an agent context this can be abused for SSRF-like behavior against internal services or sensitive network locations, especially because the skill presents itself as a reporting tool rather than a general network client.

Lp3

Medium
Category
MCP Least Privilege
Confidence
87% confidence
Finding
The skill documents capabilities to read environment variables, access the network, and read/write local files, yet no permissions are declared. That creates a transparency and least-privilege problem: users and the host may invoke a seemingly harmless visualization skill without being clearly informed that it can fetch remote data, read credentials, and modify files on disk.

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding
The public description emphasizes passive sports-information organization, but the documented behavior is materially broader: autonomous network collection, local file mutation, scheduled operation, audit gates, and credential use. This mismatch can mislead users, reviewers, and policy controls into granting trust to a skill whose actual operational surface is much larger than advertised.

Description-Behavior Mismatch

Medium
Confidence
79% confidence
Finding
The skill claims to merely organize and visualize sports data, but it also includes scheduled autonomous generation and push-style delivery of reports. Autonomous operation increases the attack surface because it can perform network access and file generation without a fresh user prompt, making misuse or silent overreach harder for users to notice.

Context-Inappropriate Capability

High
Confidence
95% confidence
Finding
The module infers avatar skin and hair traits from coarse geographic-region heuristics, including race-coded mappings such as '非洲' to darker skin palettes. This is unnecessary for the skill’s function and creates discriminatory profiling behavior that could cause harmful or offensive outputs in generated reports.

Intent-Code Divergence

High
Confidence
89% confidence
Finding
The docstring claims the module is pure standard library and '无需联网', yet later code supports live fetching from remote APIs and arbitrary URLs. In an agent setting, this kind of capability misrepresentation is dangerous because operators may approve or sandbox the skill incorrectly, leading to unexpected external communication.

Description-Behavior Mismatch

Medium
Confidence
72% confidence
Finding
The --write-gender path mutates the input JSON by writing inferred gender labels back to disk, which exceeds the skill's stated read/visualization-oriented behavior. In environments where input datasets are treated as authoritative or shared, this can silently alter source data, propagate incorrect sensitive metadata, and create integrity issues that downstream components may trust.

Context-Inappropriate Capability

Medium
Confidence
80% confidence
Finding
The script infers and enforces gender using league-name keywords and sport defaults, then uses that inference to flag or overwrite avatar metadata. Because gender is a sensitive attribute and the heuristics are simplistic, this can misclassify players or competitions and cause inaccurate labeling, especially if combined with the write-back feature that persists inferred values.

Vague Triggers

Medium
Confidence
81% confidence
Finding
The trigger phrases are extremely broad (for example, generic requests like '分析报告' or '示例演示'), which can cause the skill to activate unintentionally. Because activation leads immediately to code execution, file writes, and possibly network activity, accidental invocation is more than a UX issue; it can trigger actions the user did not clearly request.

Vague Triggers

Medium
Confidence
90% confidence
Finding
The example trigger phrase uses a very generic natural-language request ('分析一下今晚的曼城对阿森纳'), which is indistinguishable from an ordinary user query and can unintentionally activate or be interpreted as invoking the skill outside a clearly scoped context. In a sports-analysis skill this is not directly harmful like code execution, but it can cause overbroad routing, user confusion, and unintended use in contexts where the skill’s constraints are not explicit.

Missing User Warnings

Medium
Confidence
76% confidence
Finding
When `--fix` is used, the script overwrites the supplied path in place without backup, atomic write, or an explicit safety prompt. In automation or when pointed at an unintended file, this can silently destroy or corrupt source data, creating integrity and availability risk even if the content changes are not attacker-controlled.

Static analysis

No suspicious patterns detected.