Back to skill

Security audit

Taiwan Basketball

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its basketball-data purpose, but its wiki and box-score scraping import code from another skill's mutable virtual environment, creating a real isolation risk.

Install only if you are comfortable with a sports skill that writes a local cache/database and performs web scraping. Review or fix the CPBL shared-venv dependency first; this skill should vendor or declare Scrapling in its own isolated environment and restrict wiki fallback requests to the intended wiki host.

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
scripts/_wiki_api.py:22
Finding

Execution of Dependencies from a Shared, Mutable Cross-Skill Environment

Content
View full analysis

Vulnerability Details

File Location: scripts/_wiki_api.py:22-36, scripts/_tpbl_boxscore_scraper.py:14-38, and SKILL.md:272-278
Vulnerability Type: Cross-skill dependency loading and unsafe dependency isolation
Risk Level: Medium

Vulnerable Code

scripts/_wiki_api.py:22-36:

python
# Scrapling venv path (shared with the CPBL skill)
SCRAPLING_VENV = '/home/ichen/.openclaw/workspace/skills/cpbl/.venv'


def _get_stealthy_fetcher():
    """Get Scrapling StealthyFetcher (requires the CPBL skill venv)."""
    import sys
    import os
    venv_lib = f'{SCRAPLING_VENV}/lib'
    for d in os.listdir(venv_lib):
        if d.startswith('python3.'):
            site_packages = f'{venv_lib}/{d}/site-packages'
            if os.path.isdir(site_packages) and site_packages not in sys.path:
                sys.path.insert(0, site_packages)
            break
    from scrapling.fetchers import StealthyFetcher
    return StealthyFetcher

scripts/_tpbl_boxscore_scraper.py:14-38:

python
# Scrapling venv path (shared with the CPBL skill)
SCRAPLING_VENV = '/home/ichen/.openclaw/workspace/skills/cpbl/.venv'

TPBL_BOXSCORE_URL = 'https://tpbl.basketball/schedule/{game_id}/box-score'


def _debug_log(msg: str) -> None:
    """Write debug output when BASKETBALL_DEBUG=1."""
    import os
    if os.environ.get('BASKETBALL_DEBUG', '').lower() in ('1', 'true', 'yes'):
        import sys
        print(f'[DEBUG] {msg}', file=sys.stderr)


def _get_stealthy_fetcher():
    """Get Scrapling StealthyFetcher (requires the CPBL skill venv)."""
    import sys
    import os
    venv_lib = f'{SCRAPLING_VENV}/lib'
    for d in os.listdir(venv_lib):
        if d.startswith('python3.'):
            site_packages = f'{venv_lib}/{d}/site-packages'
            if os.path.isdir(site_packages) and site_packages not in sys.path:
                sys.path.insert(0, site_packages)
         
...[truncated 2901 chars]
Remediation
View remediation

Remediation Suggestions

  1. Declare Scrapling as a dependency of this Skill and install it in this Skill's own isolated virtual environment.
  2. Remove the hard-coded /home/ichen/... path and all manual insertion of external site-packages paths into sys.path.
  3. Pin direct and transitive dependency versions with a reviewed lockfile and integrity hashes where supported.
  4. Install browser artifacts through a reproducible setup process tied to reviewed versions rather than modifying another Skill's environment with --force.
  5. Ensure the Skill environment and installed packages are not writable by less-trusted users or unrelated Skills.
  6. If sharing is unavoidable, expose the scraper through a narrowly scoped service interface rather than importing executable code from another Skill's environment.
  7. Add startup validation that confirms the resolved module path belongs to the expected isolated environment.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/_wiki_api.py:184
Finding

Unvalidated Absolute URL Fetched from Remotely Controlled Wiki Content

Content
View full analysis

Vulnerability Details

File Location: scripts/_wiki_api.py:184-196
Vulnerability Type: Server-side request forgery through an unvalidated scraped link
Risk Level: Medium

Vulnerable Code

python
for link in soup.find_all('a', href=True):
    href = link['href']
    title_text = link.get_text(strip=True)
    if name in title_text and '/wiki/' in href:
        full_url = f'https://wikibasketball.dils.tku.edu.tw{href}' if href.startswith('/') else href
        try:
            page = StealthyFetcher.fetch(full_url, headless=True, wait=10000)
        except Exception:
            continue
        result['wiki_url'] = full_url
        result['name'] = title_text
        break
else:
    return result

Technical Analysis

Links beginning with / are bound to the intended wiki host, but every other matching value is accepted as a complete URL. The code only checks whether the string contains /wiki/; it does not validate the URL scheme, hostname, port, resolved IP address, or destination after redirects.

Because href originates in remotely supplied HTML, an attacker who can influence the source page can provide an absolute URL such as http://internal-service/wiki/.... If its visible title contains the searched player name, the URL passes the checks and is loaded by a browser operating in the Agent's network context.

This creates an SSRF-like primitive. Browser rendering also expands the potential request surface because a fetched page may load scripts, images, stylesheets, or other subresources. The code does not return the raw response, which limits direct extraction, but timing, error behavior, parsed content, and subsequent browser activity may still be used to probe or interact with otherwise inaccessible services.

Attack Path

  1. An attacker gains the ability to influence a basketball-wiki page or another HTML response processed by this search fallback.
  2. The attacker ...[truncated 1588 chars]
Remediation
View remediation

Remediation Suggestions

  1. Resolve links with urllib.parse.urljoin() against the expected wiki origin.
  2. Parse the resulting URL and require:
    • Scheme exactly https
    • Hostname exactly wikibasketball.dils.tku.edu.tw
    • No embedded username or password
    • No unexpected port
  3. Resolve the hostname and reject loopback, link-local, private, multicast, reserved, and unspecified IP ranges for both IPv4 and IPv6.
  4. Apply equivalent validation after every redirect, or disable cross-origin redirects.
  5. Restrict accepted paths to the expected wiki route rather than testing whether /wiki/ merely appears anywhere in the URL.
  6. Disable unnecessary browser subresources and active content when only HTML parsing is required.
  7. Add tests for absolute external URLs, protocol-relative URLs, encoded hostnames, alternate ports, redirects, DNS rebinding scenarios, and private IP destinations.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (31)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The declared description presents a broad professional basketball data skill centered on PLG and TPBL stats, scores, schedules, live data, and transactions. The supplied code chunk instead is a dedicated wiki scraper for 台灣籃球維基館, using a stealth fetcher to bypass site protection and parse player-specific wiki content such as career experience and awards. It does not implement scores, schedules, box scores, notifications, or transaction functionality in this chunk, and it explicitly targets historical/T1 and cross-league biographical data. While 'player data' is loosely related, the actual resource, scope, and primary behavior are materially different from the declared purpose.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding

The code chunk is focused specifically on notification and subscription management for upcoming PLG/TPBL games. It adds, removes, lists, and checks team subscriptions, likely using a local database layer. While this partially overlaps with the declared 'notifications' and 'schedules' functionality, the declared description is much broader and presents the skill as a general basketball data provider (stats, scores, player data, live scores, box scores, transactions). Those capabilities are not present in this chunk. More importantly, the code includes a distinct undeclared capability: persistent subscription management for teams and scheduled reminder polling. That makes the actual behavior materially narrower in some areas and different in primary interaction model than the declared description.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

The code chunk is narrowly focused on schedule retrieval and display for Taiwan professional basketball leagues. It fetches schedules, filters by team and stage, computes countdowns, and outputs schedule data. There is no evidence in this chunk of functionality for player data, live scores, box scores, notifications, transactions, or broader stats/scores handling. While 'schedules' is accurately represented, the declared description materially overstates the implemented capabilities shown here.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

The description claims a wide-ranging basketball data skill spanning stats, scores, schedules, player data, live scores, box scores, notifications, and transactions. However, this code chunk only implements standings retrieval for PLG/TPBL leagues. While standings can fall under general stats, the actual behavior shown is much narrower than the declared purpose and does not demonstrate the other major capabilities. There are no suspicious extra permissions or unrelated resource accesses, but the primary represented functionality in this chunk is materially more limited than the declared description.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The natural-language content throughout the skill forces a single language presentation, and there is no indication that users can opt into another language. The documented purpose is Taiwan basketball data, but the file does not explicitly justify the Chinese-only requirement as a locale-specific constraint or offer language choice.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill declares capabilities that clearly require network access and local file/database reads and writes, but it does not explicitly scope or constrain those permissions. This creates unnecessary trust ambiguity: a caller cannot tell from the manifest what external access and persistence the skill will use, increasing the risk of overbroad execution in environments that rely on declared tool scope for enforcement or review.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

The skill title and primary usage description are presented in Chinese-focused wording for a general basketball stats skill, and the examples and parameter explanations continue in Chinese throughout the document. There is no explicit user opt-in, language selection mechanism, or statement that the skill is intentionally limited to Chinese-speaking users, which can violate a language/locale policy requiring choice or justification.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This code contains natural-language strings and documentation that are entirely Taiwan/Traditional Chinese-specific, starting with the module title and data-source description. The file does not indicate that the locale is optional or region-scoped by user choice, which matches the policy category for forced language/locale behavior.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

This code file contains natural-language documentation entirely in Traditional Chinese, starting with the module docstring, and later returns user-facing messages in Chinese as well. Under the stated policy, forcing a specific language without user opt-in is a natural-language policy violation unless the locale restriction is explicitly justified, which is not documented here.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/_tpbl_api.py (reported line 3)May include surrounding context.

python
"""
台灣職籃 — TPBL 官方 REST API 封裝
資料來源:https://api.tpbl.basketball/api
"""

import re

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/_tpbl_api.py (reported line 51)May include surrounding context.

python
"""
台灣職籃 — TPBL 官方 REST API 封裝
資料來源:https://api.tpbl.basketball/api
"""

import re

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The returned messages such as '找不到 TPBL 球員' and '找到 ... 位球員,請輸入更精確的名稱' are natural-language outputs presented only in Chinese. Because the file does not offer language selection or state that the skill is intentionally limited to Chinese-speaking users, this conflicts with the language-choice policy.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The top-level docstring presents the skill description entirely in Traditional Chinese and does not indicate that other languages are supported or that the user can choose a preferred language. Under the stated policy, forcing a specific language or locale without opt-in is a natural-language policy concern.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The module dynamically reaches into another skill's virtual environment by hardcoding a path and prepending that environment's site-packages to sys.path before importing a browser automation dependency. This breaks isolation boundaries between skills, creates a trust dependency on external code outside this skill's package, and can lead to unintended code execution if that other environment is modified or compromised.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
81% confidence
Finding

The file’s natural-language docstring is entirely in Traditional Chinese ('台灣職籃 — 共用工具模組'), which can indicate an implicit language requirement for maintainers or users interacting with the skill. Under the stated policy, language constraints should either provide user opt-in/choice or be clearly documented as a justified region-specific limitation; this file does not include such clarification.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

This code dynamically imports packages from another skill's virtual environment by modifying sys.path to point at a hard-coded external path. That creates cross-skill trust boundaries and allows this skill's behavior and imported code to be influenced by files outside its own dependency set, which can become arbitrary code execution if the referenced environment is modified or compromised.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
85% confidence
Finding

This code makes headless network requests to an external site using a stealth fetcher, including search queries derived from the provided player name. While the module docstring describes the purpose, it does not clearly warn that user-supplied input will be transmitted to a third-party service or that stealthy fetching is used.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The inline comment at L183 says the code is trying to find matching search results after fetching search_page, but the parser is built from page.get_all_text() rather than search_page. This is an active contradiction between the documented intent and the implemented behavior, and likely causes the search fallback to inspect the wrong content.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

This code file contains natural-language descriptions that force a specific language for the skill interface, including the module docstring and CLI help text. The policy allows locale constraints only when the skill offers user choice or clearly documents and justifies a region-specific limitation, which is not present here.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The module docstring is entirely in Traditional Chinese and presents the skill as a Taiwan basketball live-score tool without any indication that language output is optional or user-selectable. Under the policy, forcing a specific language without opt-in is a natural-language locale violation unless the constraint is explicitly documented and justified.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
83% confidence
Finding

The markdown advertises '訂閱球隊、自動通知' as a feature, which implies persistent state and recurring behavior that could affect user data or system behavior. While the README later lists a local SQLite database path, it does not clearly warn users at the feature description or quick-start steps that using reminders stores subscription data locally and may perform periodic checks.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

This Python file contains natural-language documentation entirely in Traditional Chinese, and later raises a user-facing error message in Chinese as well. Because the file offers no language selection or opt-in, it may violate a language/locale policy that discourages forcing a specific language by default.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

The raised ValueError uses a Chinese-only message, which enforces a specific locale in user-visible output. Under the policy, language-specific behavior should either be optional or clearly justified as region-specific.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
78% confidence
Finding

This code file contains natural-language strings and comments exclusively in Traditional Chinese, including the module docstring and function documentation. Under the stated policy, forcing a specific language without user opt-in can be a locale/language policy violation when no alternative or opt-in is provided.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
94% confidence
Finding

The module docstring is entirely in Traditional Chinese and specifically framed for Taiwan, with no indication that alternative languages are supported. Under the policy for natural-language violations, forcing a specific language without user opt-in should be flagged unless the locale constraint is explicitly documented and justified.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.