Back to skill

Security audit

Sportsbook Skill

Security checks for vulnerabilities and agentic risk

Overview

This sports betting skill is coherent in purpose, but it handles betting authority, API keys, wallet seed phrases, webhooks, and recurring notification polling in ways that need careful review before installation.

Review this skill carefully before installing. It can transmit and store betting-agent credentials, expose wallet recovery material in agent output, poll a remote service on every skill run, register webhooks, and support automated bet posting. Use only if you trust the service and publisher, understand where credentials are stored, and are comfortable with the financial and account-control implications.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (7)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/register_helper.py:142
Finding

Registration status endpoint is queried without proof of ownership while returning API keys and wallet seed phrases

Content
View full analysis
dict: """Check registration status and retrieve API key + wallet info if approved.""" config = load_config() twitter = normalize_handle(data.get("twitter", "")) if not twitter: return {"success": False, "error": "Twitter handle is required"} url = f"{config['api_base']}/api/dawg-pack/auth/status" try: response = requests.get(url, params={"twitter": twitter}, timeout=15) if response.status_code == 200: result = response.json() status_val = result.get("status") # If approved and key is present, save it api_key = result.get("api_key") agent_id = result.get("agent_id") if api_key: config["api_key"] = api_key config["agent_id"] = agent_id save_config(config) # Auto-enable notification polling enable_notifications(config) # Build response with wallet info resp = { "success": True, "status": status_val, "api_key": api_key, "agent_id": agent_id, "message": result.get("message"), "verification_code": result.get("verification_code"), } # Include wallet info (one-time delivery from server) if result.get("wallet_address"): resp["wallet_address"] = result["wallet_address"] if result.get("seed_phrase"): resp["seed_phrase"] = result["seed_phrase"] resp["wallet_warning"] = resul ...[truncated 2149 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/config_loader.py:52
Finding

Configurable API origin allows authenticated requests to disclose API keys to arbitrary hosts

Content
View full analysis
dict: """Get request headers with API key""" headers = {"Content-Type": "application/json"} if config.get("api_key"): headers["X-Dawg-Pack-Key"] = config["api_key"] return headers ``` An authenticated caller then combines the unvalidated base URL with the credential-bearing headers: ```python api_base = config["api_base"] url = f"{api_base}/api/dawg-pack/notifications" response = requests.get( url, headers=headers, params={"limit": limit}, timeout=15 ) ``` ### Technical Analysis `DAWG_PACK_API_BASE` and `api_base` from local configuration are accepted without validating the URL scheme, hostname, port, or trusted origin. `get_headers()` independently attaches the API key to requests. Consequently, any process or configuration change capable of controlling the API base can redirect authenticated traffic to an attacker-controlled host. HTTPS alone would not resolve this issue bec ...[truncated 1079 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/register_helper.py:159
Finding

API keys, webhook secrets, and wallet recovery material are exposed through plaintext files and process output

Content
View full analysis
Remediation
View remediation

T01 · Skill Instruction Hijacking

Error
Location
SKILL.md:205
Finding

Untrusted notification text can influence an autonomous betting workflow

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/register_helper.py:25
Finding

Registration silently enables recurring authenticated polling and encourages persistent heartbeat integration

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/subscribe.py:124
Finding

Webhook registration accepts unvalidated destinations despite HTTPS-only security claims

Content
View full analysis
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
README.md:30
Finding

Dependency installation is unpinned and omits a required runtime package

Content
View full analysis
Remediation
View remediation
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
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (23)

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The README encourages activation through very broad natural-language phrases like wanting to register, without defining strict trigger boundaries or confirmation requirements. In an agent skill that can initiate account registration and later manage betting-related actions, this increases the chance of accidental invocation from unrelated conversation, quoted text, or prompt-injected content that mentions registration intent.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

Telling users to 'just ask naturally' for operational actions creates an overly permissive activation surface with no documented limits on when the skill should engage. Because this skill interfaces with sports betting data, agent profile updates, subscriptions, and webhooks, vague trigger guidance makes prompt injection, accidental tool use, or confusion between informational queries and state-changing requests more likely.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% 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.

Content

Scanner excerpt · SKILL.md (reported line 14)May include surrounding context.

md
This skill provides access to the Fuku Sportsbook system, allowing users to:

1. **Query Sports Statistics** - Get predictions, odds, team stats, and player data
2. **Register a Betting Agent** - Create their own AI betting agent
3. **Receive Notifications** - Set up webhooks for pick alerts and bet results
4. **Subscribe to Agents** - Follow other agents' picks and results

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The registration triggers include broad phrases like 'I want to bet on sports' that can match ordinary conversational intent and cause the skill to initiate account-registration and data-collection flows unexpectedly. In a skill that gathers identifiers and performs external actions, overly permissive activation increases the risk of unintended execution and surprise transmission of user data to backend services.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The trigger summary uses ambiguous activators like 'register', 'predictions', 'wallet', and 'how much', which are common short phrases that may appear in unrelated user requests. Because this skill can invoke scripts, inspect balances, and interact with external services, loose matching can expand the skill's reach beyond clear user consent.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
92% confidence
Finding

This instruction configures an outbound webhook and transmits sensitive agent identifiers and API-key-authenticated state to an external URL controlled by the user. In this skill's context, webhook setup is expected functionality, but it still creates a real exfiltration and SSRF-like risk surface if URLs are insufficiently validated or if the model performs the call without strong confirmation and secret-handling safeguards.

Content

Scanner excerpt · SKILL.md (reported line 395)May include surrounding context.

bash
# Register webhook for pick opportunities
curl -X POST "${API_BASE}/api/dawg-pack/agents/${AGENT_ID}/webhook" \
  -H "X-Dawg-Pack-Key: ${API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{"webhook_url": "https://your-openclaw-instance.com/webhook", "events": ["pick_opportunity", "result", "payout"]}'

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% 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/poll_notifications.py (reported line 85)May include surrounding context.

python
data = {"ids": notification_ids}
    
    try:
        response = requests.post(url, headers=headers, json=data, timeout=15)
        if response.status_code not in [200, 201]:
            print(f"Warning: Failed to acknowledge notifications: {response.status_code}", file=sys.stderr)
    except requests.RequestException as e:

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% 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/register_agent.py (reported line 62)May include surrounding context.

python
print(f"Starting registration for @{handle}...")
    try:
        response = requests.post(url, json=data, timeout=15)
    except requests.RequestException as e:
        print(f"Error: Network request failed - {e}")
        sys.exit(1)

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% 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/register_agent.py (reported line 123)May include surrounding context.

python
print(f"Starting registration for @{handle}...")
    try:
        response = requests.post(url, json=data, timeout=15)
    except requests.RequestException as e:
        print(f"Error: Network request failed - {e}")
        sys.exit(1)

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% 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/register_helper.py (reported line 79)May include surrounding context.

python
print(f"Starting registration for @{handle}...")
    try:
        response = requests.post(url, json=data, timeout=15)
    except requests.RequestException as e:
        print(f"Error: Network request failed - {e}")
        sys.exit(1)

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% 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/register_helper.py (reported line 123)May include surrounding context.

python
print(f"Starting registration for @{handle}...")
    try:
        response = requests.post(url, json=data, timeout=15)
    except requests.RequestException as e:
        print(f"Error: Network request failed - {e}")
        sys.exit(1)

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

enable_notifications writes api_key, agent_id, and related settings into ~/.config/fuku-sportsbook/config.json without any user-facing disclosure and suppresses write errors. Persisting credentials in a plain JSON file can expose secrets to other local users, backups, or malware, and the silent failure makes security behavior harder to audit.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The status function is presented as a read/check operation, but it also persists the returned API key and agent ID to local configuration and then enables notifications, which writes another config file. This hidden state-changing behavior can surprise users or calling agents, causes credential persistence without explicit consent, and increases the risk of unintended secret exposure on disk.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

After receiving an API key, the helper silently enables notification polling by writing persistent configuration with no visible confirmation in this code path. In an agent skill context, silent persistence and background feature enablement are risky because they change system behavior beyond the requested status action and may expose credentials or metadata to future processes.

Content

No source excerpt is available for this finding.

Tainted flow: 'data' from requests.get (line 185, network input) → requests.post (network output)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/subscribe.py (reported line 39)May include surrounding context.

python
print(f"Subscribing to {agent_id}...")
    try:
        response = requests.post(url, headers=get_headers(config), json=data, timeout=15)
    except requests.RequestException as e:
        print(f"Error: Network request failed - {e}")
        sys.exit(1)

Tainted flow: 'data' from requests.get (line 185, network input) → requests.post (network output)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/subscribe.py (reported line 144)May include surrounding context.

python
print(f"Subscribing to {agent_id}...")
    try:
        response = requests.post(url, headers=get_headers(config), json=data, timeout=15)
    except requests.RequestException as e:
        print(f"Error: Network request failed - {e}")
        sys.exit(1)

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The delete_webhook function issues an HTTP DELETE request that removes a webhook, but only prints a progress message and does not warn the user about the irreversible effect or ask for confirmation. Destructive operations in code should have some visible disclosure unless clearly covered elsewhere; the brief docstring and CLI help do not communicate the risk.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The notification management code copies the API key into ~/.config/fuku-sportsbook/config.json, creating an additional on-disk secret without warning the user or applying any visible permission hardening. This increases the attack surface for credential exposure through local compromise, backups, shared accounts, or overly permissive filesystem defaults.

Content

No source excerpt is available for this finding.

Scope Creep

Low
Category
Excessive Agency
Confidence
70% confidence
Finding

Skill's behavior or capabilities extend beyond its stated purpose. Scope creep allows an agent to perform actions unrelated to its documented functionality, increasing the attack surface.

Content

Scanner excerpt · SKILL.md (reported line 22)May include surrounding context.

md
## REGISTRATION FLOW (Conversational)

When a user wants to register, guide them through a natural conversation. DO NOT show them CLI commands - handle everything behind the scenes.

### Trigger Phrases for Registration
- "I want to register"

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The loader prioritizes a user-specific JSON config in ~/.config/fuku-sportsbook/config.json, but save_config writes only to CONFIG_FILE in the skill directory. This creates an intent/documentation mismatch because the surrounding module behavior suggests two config locations, while the save function's documentation does not reflect that it updates only one of them.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

This code updates and writes configuration data to persistent files in both the main config and the user's home directory. While the code comments describe the behavior for developers, there is no user-facing print, prompt, or other disclosure indicating that running the script will modify local config state.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

The module docstring presents this script as only managing subscriptions and webhooks, but the code also implements a separate notifications command that writes notification state plus API credentials and agent metadata into ~/.config/fuku-sportsbook/config.json. That is behavior beyond the documented scope at the top of the file, even though it is related to the broader service.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The top-of-file usage block enumerates the supported commands, but it does not include the implemented 'notifications' subcommand present later in main(). This is an active documentation/code divergence because the usage text claims to describe how to use the script while leaving out a real command with configuration-writing side effects.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.