Back to skill

Security audit

Odds Movement Monitor 赔率异动监控

Security checks for vulnerabilities and agentic risk

Overview

This sports-odds monitoring skill mostly matches its stated purpose, but its paid billing code embeds a live-looking billing API key and can charge an environment-selected user identity without clear in-artifact authorization safeguards.

Install only if you are comfortable with a paid skill that contacts both The Odds API and skillpay.me. The publisher should remove the embedded billing key, bind charges to a verified platform identity instead of SKILLPAY_USER_ID, and add an explicit confirmation or trusted host-controlled charge flow before this is treated as low-risk.

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

T09 · Insecure Skill Coding Practices

Error
Location
payment.py:11
Finding

Hard-Coded Billing Credential and Unverified Caller-Controlled Billing Identity

Content
View full analysis
float: """查询用户余额""" try: resp = requests.get( f"{BILLING_API_URL}/api/v1/billing/balance", params={"user_id": user_id}, headers=HEADERS, timeout=10 ) if resp.status_code == 200: return resp.json().get("balance", 0.0) return 0.0 except Exception as e: print(f"⚠️ 查询余额失败: {e}") return 0.0 def charge_user(user_id: str) -> dict: """ 对用户进行扣费 返回: {"ok": bool, "balance": float, "payment_url": str|None} """ try: resp = requests.post( f"{BILLING_API_URL}/api/v1/billing/charge", headers=HEADERS, json={ "user_id": user_id, "skill_id": SKILL_ID, "amount": PRICE_PER_CALL, }, timeout=10 ) data = resp.json() if data.get("success"): return { "ok": True, "balance": data.get("balance", 0.0), "payment_url": None } else: return { "ok": False, "balance": data.get("balance", 0.0), "payment_url": data.get("payment_url") } except Exception as e: print(f"⚠️ 扣费请求失败: {e}") return {"ok": False, "balance": 0.0, "payment_url": None, "error": str(e)} def get_payment_lin ...[truncated 3578 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (25)

Tainted flow: 'user_id' from os.environ.get (line 96, credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · payment.py (reported line 29)May include surrounding context.

python
def check_balance(user_id: str) -> float:
    """查询用户余额"""
    try:
        resp = requests.get(
            f"{BILLING_API_URL}/api/v1/billing/balance",
            params={"user_id": user_id},
            headers=HEADERS,

Tainted flow: 'user_id' from os.environ.get (line 96, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
98% confidence
Finding

The code automatically charges whatever account is named by SKILLPAY_USER_ID from the runtime environment, without authenticating that the caller is authorized to bill that identity. In a shared or manipulated execution environment, an attacker could set or influence this variable and trigger unauthorized charges against another user's billing account.

Content

Scanner excerpt · payment.py (reported line 48)May include surrounding context.

python
返回: {"ok": bool, "balance": float, "payment_url": str|None}
    """
    try:
        resp = requests.post(
            f"{BILLING_API_URL}/api/v1/billing/charge",
            headers=HEADERS,
            json={

Tainted flow: 'user_id' from os.environ.get (line 96, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · payment.py (reported line 79)May include surrounding context.

python
def get_payment_link(user_id: str, amount: float = 5.0) -> str:
    """生成充值链接"""
    try:
        resp = requests.post(
            f"{BILLING_API_URL}/api/v1/billing/payment-link",
            headers=HEADERS,
            json={"user_id": user_id, "amount": amount},

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

This finding indicates a severe description-to-behavior mismatch: the advertised sports-odds functionality is absent, while undeclared network communication to an external billing API and a hardcoded API key are present. In the context of a paid skill, that combination strongly suggests deceptive monetization or covert external interaction, which could expose users to unauthorized billing, tracking, or abuse of embedded credentials.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

This finding indicates a severe description-to-behavior mismatch: the advertised sports-odds functionality is absent, while undeclared network communication to an external billing API and a hardcoded API key are present. In the context of a paid skill, that combination strongly suggests deceptive monetization or covert external interaction, which could expose users to unauthorized billing, tracking, or abuse of embedded credentials.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

verify_payment immediately invokes charge_user and require_payment calls it on startup, so the code path attempts to debit funds before presenting a user-facing warning or obtaining confirmation. This creates a dark-pattern style auto-charge risk and can result in unauthorized or surprising financial transactions.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The README presents the skill identity and behavior in Chinese only, with no indication that users can choose another language or that the skill is intentionally limited to a Chinese-speaking/regional context. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
82% confidence
Finding

The skill appears to require network and environment access but does not declare any explicit tool scope or permissions. This creates a transparency and least-privilege problem: reviewers and users cannot verify what external access the skill may exercise, increasing the chance of hidden data exfiltration, unauthorized outbound requests, or unsafe runtime behavior.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The natural-language content of the skill, including its description and user-facing documentation, is presented only in Chinese. This can violate language/locale policy when no user opt-in, alternative language, or justification for the locale restriction is provided.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

This Python file contains user-facing natural-language descriptions entirely in Chinese, starting with the module docstring naming the algorithm in Chinese. Under the policy rule, forcing a specific language without user opt-in is a locale/language policy violation unless the constraint is explicitly documented and justified, 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
95% confidence
Finding

The skill returns recommendation strings and prints demo output in Chinese only, such as the recommendation messages and console labels. Because these are user-facing outputs with no language choice or justification for a Chinese-only locale, they violate the natural-language language/locale policy described in SQP-3.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This Python file contains user-facing natural-language strings, headings, recommendations, and usage instructions exclusively in Chinese. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation unless the locale constraint is explicitly justified, which is not present here.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The script prepends a home-directory workspace path to sys.path, causing imports to resolve from a user-writable location outside the skill package. That enables module hijacking or execution of unexpected local code if that directory contains a malicious or tampered change_detector module, which is unnecessary for a demo script and weakens trust boundaries.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

This is a code file, so natural-language strings in docstrings and console output are in scope. The skill presents its description and operational messages only in Chinese, and nowhere offers a language/locale option or explains that the tool is intentionally region-specific, which fits the language-policy violation criteria.

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 · config.json (reported line 15)May include surrounding context.

json
def __init__(self, api_key: Optional[str] = None):
        self.api_key = api_key or os.getenv("ODDS_API_KEY")
        self.base_url = "https://api.the-odds-api.com/v4"
    
    async def fetch_sports(self) -> List[Dict]:
        """获取支持的体育项目"""

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 · monitor.py (reported line 210)May include surrounding context.

python
def __init__(self, api_key: Optional[str] = None):
        self.api_key = api_key or os.getenv("ODDS_API_KEY")
        self.base_url = "https://api.the-odds-api.com/v4"
    
    async def fetch_sports(self) -> List[Dict]:
        """获取支持的体育项目"""

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The module description and multiple user-facing strings are presented in Chinese, including payment and failure messages, but the skill does not provide user opt-in or a documented locale constraint. This can violate language/locale policy when users are forced into a specific language without choice.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
95% confidence
Finding

This external transmission sends billing instructions, including user_id, skill_id, and amount, to a third-party payment service using a hard-coded API credential embedded in the source. If the code is exposed or reused, the credential can be abused to initiate fraudulent charges or interact with the billing account without authorization.

Content

Scanner excerpt · payment.py (reported line 48)May include surrounding context.

python
返回: {"ok": bool, "balance": float, "payment_url": str|None}
    """
    try:
        resp = requests.post(
            f"{BILLING_API_URL}/api/v1/billing/charge",
            headers=HEADERS,
            json={

External Transmission

Medium
Category
Data Exfiltration
Confidence
94% confidence
Finding

The payment-link request transmits user billing data to an external provider using the same hard-coded API key present in the file. Exposure of that credential allows unauthorized creation of payment links and abuse of the billing integration, which is especially sensitive because this skill is unrelated to payment processing as its primary business function.

Content

Scanner excerpt · payment.py (reported line 79)May include surrounding context.

python
def get_payment_link(user_id: str, amount: float = 5.0) -> str:
    """生成充值链接"""
    try:
        resp = requests.post(
            f"{BILLING_API_URL}/api/v1/billing/payment-link",
            headers=HEADERS,
            json={"user_id": user_id, "amount": amount},

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The skill reads a runtime environment variable to determine which user account to bill, even though this sports-odds skill's core function does not inherently require access to ambient environment state. In many agent/runtime deployments, environment variables are mutable deployment metadata rather than authenticated user identity, so using them for financial operations can enable account mix-ups or abuse.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
83% confidence
Finding

The manifest uses Chinese for the main description and multiple user-facing names/notes, with no indication that the skill is region-specific or that users can opt into another language. This can violate language/locale policy when a skill implicitly assumes one language for all users.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

The dependency is specified with a lower-bound version only, which allows future installs to resolve to different releases over time. This weakens build reproducibility and can unintentionally pull in vulnerable or breaking versions, especially significant for a network-facing HTTP library like aiohttp.

Content

Scanner excerpt · requirements.txt (reported line 1)May include surrounding context.

text
aiohttp>=3.8.0
requests>=2.28.0

Unverifiable Dependency: aiohttp has 16 known advisory(ies) (CVE-2024-52303 (aiohttp has a memory leak when middleware is enabled when requesting a resource ); CVE-2026-54279 (aiohttp: Host-Only Cookies Become Domain Cookies After CookieJar Persistence); CVE-2026-34514 (AIOHTTP has CRLF injection through multipart part content type header constructi) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
84% confidence
Finding

aiohttp has multiple published advisories, and because the manifest does not pin a version, there is no way to verify whether deployed environments are using an affected release. In a real-time odds monitoring skill, HTTP client behavior is core functionality, so unresolved library risk is more relevant than in an offline-only tool.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

The requests package is also unpinned, so dependency resolution is non-deterministic and may bring in versions with known security defects. For an agent skill that likely performs remote HTTP calls, this increases supply-chain and patch-management risk.

Content

Scanner excerpt · requirements.txt (reported line 2)May include surrounding context.

text
aiohttp>=3.8.0
requests>=2.28.0

Unverifiable Dependency: requests has 16 known advisory(ies) (CVE-2014-1830 (Exposure of Sensitive Information to an Unauthorized Actor in Requests); CVE-2024-47081 (Requests vulnerable to .netrc credentials leak via malicious URLs); CVE-2024-35195 (Requests `Session` object does not verify requests after making first request wi) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
84% confidence
Finding

requests has known advisories, and the absence of version pinning makes it impossible to determine whether installs are vulnerable. Since this skill appears to interact with external services for odds data and payment-related integration context exists, unsafe HTTP dependency selection could expose network, credential, or request-handling weaknesses.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.