Back to skill

Security audit

cpbl

Security checks for vulnerabilities and agentic risk

Overview

This CPBL sports skill is mostly purpose-aligned, but it explicitly instructs agents to use stealth browser automation to bypass a protected website and installs unpinned browser/dependency components.

Review before installing. The skill is suitable only if you are comfortable with automated requests to CPBL-related sites and with installing unpinned Scrapling/Patchright browser components. Avoid using the stealth wiki-fetching path unless you have authorization and accept the site-policy and operational risks.

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

T08 · Insecure Dependencies

Warning
Location
SKILL.md:149
Finding
Unpinned Runtime Packages and Browser Components Permit Supply-Chain Code Execution## Vulnerability Details **File Location**: `SKILL.md:149`; `README.md:104-106`; `scripts/_cpbl_api.py:4-6`; `scripts/cpbl_games.py:4-6`; `scripts/cpbl_live.py:4-7`; `scripts/cpbl_schedule.py:4-6`; `scripts/cpbl_standings.py:4-7`; `scripts/cpbl_stats.py:4-7`; `scripts/cpbl_twbsball.py:4-6` **Vulnerability Type**: Unpinned third-party runtime and browser dependencies **Risk Level**: Medium ### Vulnerable Code `SKILL.md:149`: ```bash cd skills/cpbl && uv run --with "scrapling[ai]" --with curl_cffi patchright install ``` `README.md:104-106`: ```bash cd skills/cpbl && uv venv && uv pip install -e . .venv/bin/scrapling install --force ``` Representative PEP 723 dependency declaration from `scripts/_cpbl_api.py:4-6`: ```python # dependencies = [ # "scrapling[ai]", # ] ``` The same unpinned `scrapling[ai]` declaration is present in the other listed scripts. `beautifulsoup4` is also declared without a version constraint in `scripts/cpbl_standings.py` and `scripts/cpbl_stats.py`. ### Technical Analysis The scripts use `uv run` with PEP 723 dependency declarations that do not pin exact versions or verify package hashes. The documented setup procedure also invokes package-managed browser installation, including a forced installation command, without pinning or validating the downloaded browser revision. Consequently, the code that actually runs can change after this Skill has been reviewed. Package resolution may retrieve a later release of `scrapling`, `curl_cffi`, `patchright`, `beautifulsoup4`, or their transitive dependencies. Installation hooks, imported package initialization code, and browser installers execute with the permissions of the user running the Skill. The audit found no evidence that the currently referenced packages or current project code are malicious. The issue is the absence of controls that bind execution to reviewed dependency artifacts. ### Attack Path 1. ...[truncated 1519 chars]
Remediation
## Remediation Suggestions 1. Pin every direct dependency to an exact reviewed version, including all PEP 723 declarations. 2. Generate and commit a lockfile that records the complete transitive dependency graph. 3. Require cryptographic hashes for downloaded Python distributions where supported. 4. Pin the browser engine and browser revision rather than installing whichever version is current. 5. Remove `--force` from normal installation instructions so existing reviewed components are not silently replaced. 6. Restrict package resolution to explicitly trusted registries and disable untrusted supplemental indexes. 7. Separate dependency and browser installation from routine Skill execution. Require explicit user approval before downloading executable components. 8. Run installation and browser automation inside a sandbox with restricted filesystem access, environment-variable access, and outbound networking. 9. Add automated dependency review, provenance verification, and vulnerability scanning to the release process. 10. Keep dependency versions consistent across all scripts so independent `uv run` resolutions cannot produce different runtime environments.

T09 · Insecure Skill Coding Practices

Note
Location
scripts/_cpbl_api.py:27
Finding
Predictable Shared Temporary File Enables Symbolic-Link File Overwrite## Vulnerability Details **File Location**: `scripts/_cpbl_api.py:27,70-90` **Vulnerability Type**: Unsafe predictable temporary file and non-atomic token-cache creation **Risk Level**: Low ### Vulnerable Code `scripts/_cpbl_api.py:27`: ```python TOKEN_CACHE_FILE = Path(tempfile.gettempdir()) / 'cpbl_csrf_token.txt' ``` `scripts/_cpbl_api.py:70-90`: ```python def _load_token_cache(self): """載入快取的 CSRF token""" if TOKEN_CACHE_FILE.exists(): try: with open(TOKEN_CACHE_FILE, 'r') as f: data = json.load(f) self.csrf_token = data.get('token') expire_str = data.get('expire') if expire_str: self.token_expire = datetime.fromisoformat(expire_str) except (json.JSONDecodeError, KeyError, OSError, ValueError) as e: print(f'⚠️ CSRF token 快取讀取失敗: {e}', file=sys.stderr) def _save_token_cache(self): """儲存 CSRF token 到快取""" data = { 'token': self.csrf_token, 'expire': self.token_expire.isoformat() if self.token_expire else None } with open(TOKEN_CACHE_FILE, 'w') as f: json.dump(data, f) ``` ### Technical Analysis The token cache is stored under a fixed, globally predictable name in the operating system temporary directory. The code checks and opens the path using ordinary filesystem operations that follow symbolic links. It does not securely create the file, verify ownership, reject links, set explicit owner-only permissions, or atomically replace an existing cache. On a shared system where another local user can write to the temporary directory, an attacker can pre-create `cpbl_csrf_token.txt` as a symbolic link to another path. When the victim refreshes the CPBL token, opening the cache in write mode follows the link and truncates the linked target before writing JSON. The cached value is an anonymous CSRF token obtained from the ...[truncated 1782 chars]
Remediation
## Remediation Suggestions 1. Store the cache in an owner-private user cache directory instead of the shared temporary directory. 2. Create the parent directory with permissions that allow access only to the owning user. 3. Create new cache files with mode `0600` and exclusive-creation semantics. 4. Reject symbolic links and verify that any existing cache is a regular file owned by the current user. 5. Write data to a securely created temporary file in the same private directory, flush it, and atomically replace the final cache with `os.replace`. 6. Avoid a check-then-open sequence because it introduces a time-of-check to time-of-use race. 7. Consider keeping the short-lived anonymous CSRF token only in process memory; this removes the cross-process filesystem risk entirely. 8. If cross-process caching is necessary, use a platform-appropriate secure cache API and define cleanup behavior for expired tokens.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (31)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The description presents a general-purpose CPBL information skill, especially for scores, schedules, live results, standings, news, awards, and history. The supplied code instead targets a narrow advanced-statistics use case using stats.cpbl.com.tw endpoints for leaderboards, league summaries, player logs, and player info. While 'player stats' partially overlaps, the primary purpose is materially different and much narrower than declared, and it also includes advanced tracking/statcast-style analytics not explicitly described. Therefore this is a clear description-behavior mismatch.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The implemented script is narrowly focused on querying completed CPBL games and enriching them with box-score summary details from CPBL APIs. It explicitly filters out games that have not ended, so it does not provide live games or upcoming schedules despite the declared description mentioning both. It also does not compute or retrieve standings, league rankings, general player statistics pages, news, awards, or Taiwan baseball history. Some declared areas such as 二軍, 熱身賽, and 總冠軍賽 are partially supported through the kind filter, but the overall declared purpose is much broader than the actual behavior. Therefore the description materially overstates the skill’s capabilities.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding
The description presents a broad CPBL information skill, but this code chunk only covers one subset: live/scheduled game lookup and box-score-style game details. It fetches games by date, infers status, gets live inning info, and formats output as JSON/text. It does not show functionality for standings, league/player statistical databases, news, awards, second team coverage as a distinct feature, or historical knowledge retrieval. While the implemented behavior is consistent with part of the description (scores, schedules, live games), the declared purpose materially overstates the capabilities represented by this code chunk, so this should be flagged as a mismatch.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
The declared description promises a comprehensive CPBL information skill spanning many content types. However, this code chunk only implements schedule retrieval and limited score inclusion for completed games, via fetch_game_datas and filtering/output logic. It does not show functionality for live score updates, standings/rankings, player statistics, news retrieval, award data, or historical fact lookup. Parts of the declared scope such as 二軍, 熱身賽, and 總冠軍賽 are partially supported through the kind parameter, but the overall declared purpose is materially broader than the actual implemented behavior in this chunk.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The code chunk is narrowly focused on CPBL standings retrieval. It calls a standings-specific API endpoint, parses HTML tables labeled team-versus records and team pitching/batting/fielding stats, and supports only year and league kind (一軍/二軍). There is no implementation for schedules, live game data, player-level statistics, news retrieval, awards, broader historical facts, or other CPBL content named in the description. While some declared areas like 二軍 are partially supported, the declared purpose substantially overstates the implemented functionality of this code chunk, so this is a description/behavior mismatch.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The code chunk only supports querying player leaderboard statistics (batting or pitching) for a given year, team, and league level (A/W, including 二軍). It does not implement score lookup, schedule retrieval, live game status, standings, news, awards, historical facts, or other broad CPBL coverage described in the declaration. While the declared description includes player stats and 二軍, the overall declared purpose substantially overstates the skill’s capabilities compared with this code’s actual behavior.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The declared description suggests a comprehensive CPBL information skill with multiple topical capabilities (scores, schedules, live games, standings, player stats, news, awards, and historical CPBL facts). The supplied code only fetches raw text from arbitrary pages on the Taiwan Baseball Wiki by title. While this could support some historical CPBL fact lookup, it does not implement most of the declared capabilities, especially live/current data such as scores, schedules, standings, rankings, or news. Its actual primary purpose is generic wiki page scraping, not a CPBL-specific query tool.

Context-Inappropriate Capability

Medium
Confidence
94% confidence
Finding
The README explicitly promotes using Scrapling StealthyFetcher to bypass Anubis anti-bot protections on twbsball. Even though the skill’s purpose is CPBL information lookup, documenting anti-bot evasion introduces a reusable browser-automation capability that can be repurposed against protected sites and encourages access patterns that may violate site controls or terms.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The README describes bypassing anti-bot protections but provides no warning about legal, contractual, or operational risks. Omitting those cautions normalizes potentially unauthorized scraping and may cause users or downstream agents to perform risky access without understanding compliance implications.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
This section gives concrete setup and code instructions for installing and running a stealth browser against a protected site, materially operationalizing the evasion capability. That goes beyond ordinary documentation for a sports-info skill and lowers the barrier to misuse by turning anti-bot circumvention into a copy-paste workflow.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The setup instructions and runnable code example tell users how to deploy a stealth browser against a protected site but do not include a clear warning or usage boundary. This makes the documentation more dangerous because it is immediately actionable and may be reused outside the CPBL context for evasive scraping.

Lp3

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding
The skill instructs use of local scripts, schedule cache files, and multiple network sources, but it does not declare any explicit tool scope such as allowed tools or permissions. In an agent environment, this expands ambiguity around what filesystem and network access the skill may exercise, increasing the chance of over-privileged execution or unintended data access.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
The manifest description explicitly says the skill is for 'Taiwan users' and is written as if Chinese/Taiwan-specific usage is the default. This creates a locale constraint in the skill's natural-language policy surface without documenting opt-in, alternatives, or a clear compliance-based justification.

Session Persistence

Medium
Category
Rogue Agent
Content
- **狀態:** ❌ 測試時返回 500 錯誤,需要更多參數

### 3. 統計數據
- **Endpoint:** `/stats/toplistaction`
- **方法:** POST
- **必要 Headers:**
  - `RequestVerificationToken`: CSRF token
Confidence
75% 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
94% confidence
Finding
The entire skill-facing document is written in Traditional Chinese, and there is no indication that users may choose another language or that the skill is limited to a Chinese-speaking or Taiwan-specific audience. Under the policy, forcing a specific language without user opt-in is a natural-language locale violation.

Intent-Code Divergence

Medium
Confidence
92% confidence
Finding
Lines L046-L049 state that standings can now be fetched and parsed directly from the official endpoint, but later the same document says the project is unable to successfully fetch CPBL official data and that AJAX endpoint problems remain unresolved. This is an active contradiction in the documentation about the skill's real capabilities, not merely an omission or partial detail.

Intent-Code Divergence

Medium
Confidence
90% confidence
Finding
The example output at L071-L080 shows all standings tables as empty due to API problems, which conflicts with the earlier assertion at L046-L049 and L066 that the standings script can retrieve and parse official standings data. This creates a direct intent/capability inconsistency in the file's own documentation.

Description-Behavior Mismatch

Medium
Confidence
93% confidence
Finding
The manifest describes a broad CPBL query skill covering live games, player stats, and news, but the observed behavior in the log shows cpbl_games, cpbl_stats, and cpbl_news returning empty results with explicit notes that the functionality is not fully implemented. This is a semantic mismatch between the advertised capability and what the skill currently delivers.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The code persists a CSRF token to a predictable file in the system temporary directory without setting restrictive permissions or scoping it to the current user/session. While this token is not as sensitive as a password, local users or processes on the same host may be able to read or replace it, enabling request spoofing against the CPBL service or causing cross-process leakage.

Missing User Warnings

Medium
Confidence
85% confidence
Finding
The module sends POST requests containing the provided data payload to cpbl.com.tw via urllib, which is a network transmission of user- or system-provided data. While network access is central to the module's purpose, this function does not provide any user-facing notice about what data is sent, and the file itself contains no explicit disclosure beyond technical implementation details.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
This code file includes the primary description and CLI help text in Chinese, which effectively forces a specific language for users. The policy allows fixed locale behavior only when the constraint is explicitly justified or when users are offered a language/locale choice, neither of which is present here.

Description-Behavior Mismatch

Medium
Confidence
92% confidence
Finding
The implementation materially diverges from the skill’s declared CPBL-focused purpose by scraping TWBSball wiki pages instead of using a source aligned to live scores, schedules, standings, or stats. This is dangerous because it can cause the agent to retrieve data from an unintended source, return stale or incorrect information, and violate user or platform expectations about what external services the skill accesses.

Natural-Language Policy Violations

Low
Confidence
87% confidence
Finding
The natural-language content consistently forces a specific language/locale for all instructions and labels. The policy allows locale constraints when they are explicitly justified, but this file does not state that the skill is intentionally limited to Chinese-speaking or Taiwan-specific users.

Missing User Warnings

Low
Confidence
83% confidence
Finding
The document explicitly instructs implementers to extract a CSRF token from cpbl.com.tw pages and send direct AJAX POST requests to third-party endpoints. In an agent skill, undocumented outbound network access to a third-party site can surprise users, create compliance/privacy issues, and normalize bypass-like interaction patterns with anti-CSRF mechanisms even if the immediate use case is sports data retrieval.

Natural-Language Policy Violations

Low
Confidence
91% confidence
Finding
This plain-text log and the embedded CLI help/output are entirely presented in Traditional Chinese, with no indication that the skill offers language selection or that the skill is explicitly limited to a Chinese-speaking or Taiwan-specific user context. Under the policy rule, forcing a specific language without user opt-in can be a natural-language policy violation.

Static analysis

No suspicious patterns detected.