Back to skill

Security audit

Betbud Prediction Skill

Security checks for vulnerabilities and agentic risk

Overview

The skill is documented as generating a JSON prediction-market proposal, but its code can automatically use a private key to create an on-chain market and post records to an external backend.

Review this skill carefully before installing. Do not run it with a funded wallet or production credentials unless you intentionally want it to create blockchain markets and publish event records to betbud.live without an approval prompt. The exposed Bubble token should be rotated by its owner.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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 (3)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
skill.py:222
Finding

Undisclosed Autonomous Use of a Private Key for a Payable Blockchain Transaction

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
skill.py:143
Finding

Untrusted External Content and LLM Output Directly Control a Financial Transaction Parameter

Content
View full analysis
start: text = text[start:end] text = text.replace('\n', ' ').replace(' ', ' ').strip() print(f"Claude raw: {text[:200]}") try: return json.loads(text) except Exception as e: print(f"JSON parse error: {str(e)}") print(f"Raw text: {text}") raise ``` ```python tx = contract.functions.openNewMarket(duration_days).build_transaction({ ``` ```python proposal = analyze_with_claude(topics, recent) print("Proposal:", json.dumps(proposal, indent=2)) image_url = get_professional_image(proposal["question"], proposal.get("category", "Crypto")) market_num, t ...[truncated 2680 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
skill.py:252
Finding

Hard-Coded Bearer Credential and Undisclosed Wallet Disclosure to an External Service

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (18)

Tainted flow: 'headers' from os.getenv (line 194, 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 · skill.py (reported line 122)May include surrounding context.

python
params = {"query": query, "count": limit}
    
    try:
        response = requests.get(url, headers=headers, params=params, timeout=10)
        response.raise_for_status()
        data = response.json()
        tweets = data.get('tweets', []) or data.get('data', [])

Tainted flow: 'headers' from os.getenv (line 194, 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 · skill.py (reported line 138)May include surrounding context.

python
params = {"query": query, "count": limit}
    
    try:
        response = requests.get(url, headers=headers, params=params, timeout=10)
        response.raise_for_status()
        data = response.json()
        tweets = data.get('tweets', []) or data.get('data', [])

Tainted flow: 'headers' from os.getenv (line 194, 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 · skill.py (reported line 202)May include surrounding context.

python
}
    
    try:
        response = requests.get(url, headers=headers, params=params)
        response.raise_for_status()
        data = response.json()
        image_url = data['results'][0]['urls']['regular'] if data['results'] else ""

Tainted flow: 'headers' from os.getenv (line 194, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
99% confidence
Finding

The skill sends data to an external Bubble backend using a hardcoded bearer token embedded in source code. Hardcoded credentials are easily leaked through source distribution, logs, backups, or repository access, enabling unauthorized writes to the backend and potential abuse of the associated account.

Content

Scanner excerpt · skill.py (reported line 284)May include surrounding context.

python
}
    
    try:
        resp = requests.post(url, headers=headers, json=data)
        resp.raise_for_status()
        print("Bubble registered successfully:", resp.json())
    except Exception as e:

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · skill.py (reported line 18)May include surrounding context.

python
UNSPLASH_ACCESS_KEY = os.getenv("UNSPLASH_ACCESS_KEY")

if not all([TWITTERAPI_IO_KEY, ANTHROPIC_API_KEY, RPC_URL, PRIVATE_KEY, UNSPLASH_ACCESS_KEY]):
    print("ERROR: Missing keys in .env")
    exit(1)

client = Anthropic(api_key=ANTHROPIC_API_KEY)

Ssd 1

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The LLM prompt feeds untrusted tweet content directly into the model and asks it to generate actionable structured output, with no instruction to ignore embedded commands or treat posts as hostile content. This creates a prompt-injection path where adversarial tweets can steer proposal generation, bypass intended constraints, or influence downstream blockchain and backend actions.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The skill can sign and broadcast blockchain transactions using a locally loaded private key, causing real privileged financial actions on-chain. Because market creation is triggered automatically from externally sourced content and LLM output, the code creates a direct path from untrusted inputs to spending funds and changing blockchain state.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The code spends funds and submits a signed blockchain transaction without any explicit user confirmation, review step, or warning. In this context, autonomous on-chain execution based on untrusted social-media inputs and LLM output is especially dangerous because mistakes or manipulations can immediately cause irreversible financial loss.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The skill writes records to an external Bubble backend with a hardcoded bearer token and no evident business-logic safeguards. This gives the code persistent ability to create or alter external records, and if the token is exposed or the skill is misused, an attacker can spam, deface, or corrupt the backend dataset.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

The script accesses multiple sensitive environment variables, including a blockchain private key, and uses them to authenticate API calls and sign transactions. Aside from a missing-keys error, there is no warning comment, docstring, or user disclosure that execution depends on high-sensitivity credentials and can act with them.

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

python
def get_hot_topics(category="crypto", limit=10):
    since = (datetime.now() - timedelta(days=2)).strftime("%Y-%m-%d")
    query = f"{category} (debate OR controversy OR hot OR trending) min_faves:100 since:{since} filter:has_engagement"
    url = "https://api.twitterapi.io/twitter/tweet/advanced_search"
    headers = {"x-api-key": TWITTERAPI_IO_KEY}
    params = {"query": query, "count": limit}

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

python
def get_hot_topics(category="crypto", limit=10):
    since = (datetime.now() - timedelta(days=2)).strftime("%Y-%m-%d")
    query = f"{category} (debate OR controversy OR hot OR trending) min_faves:100 since:{since} filter:has_engagement"
    url = "https://api.twitterapi.io/twitter/tweet/advanced_search"
    headers = {"x-api-key": TWITTERAPI_IO_KEY}
    params = {"query": query, "count": limit}

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The skill aggregates social-media content and sends it to an external LLM provider, which is a material data egress path. Even if the data is mostly public, this expands the trust boundary and can leak internal context such as recent prediction history, operator workflow details, or proprietary prompt structure to a third party without clear controls.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The skill transmits collected tweet content and generated proposal material to Anthropic without any visible disclosure or consent mechanism. This is risky because it moves externally collected data and internal cache-derived context across trust boundaries to a third-party provider, which may violate user expectations or organizational policy.

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

python
raise

def get_professional_image(question, category):
    url = "https://api.unsplash.com/search/photos"
    headers = {"Authorization": f"Client-ID {UNSPLASH_ACCESS_KEY}"}
    params = {
        "query": f"{category} finance betting prediction market professional illustration",

External Transmission

Medium
Category
Data Exfiltration
Confidence
95% confidence
Finding

This external POST sends internally generated event records to a third-party Bubble backend using privileged authentication. In this skill, that transmission is more dangerous because it is coupled with a hardcoded bearer token and writes persistent records based on untrusted and LLM-shaped inputs.

Content

Scanner excerpt · skill.py (reported line 284)May include surrounding context.

python
}
    
    try:
        resp = requests.post(url, headers=headers, json=data)
        resp.raise_for_status()
        print("Bubble registered successfully:", resp.json())
    except Exception as e:

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

Medium
Category
Data Flow
Confidence
90% confidence
Finding

Data incorporated into the POST body is derived from untrusted external sources, including tweets, LLM output based on those tweets, and third-party API responses. Forwarding untrusted content to another backend without validation can poison stored records, inject misleading content, or trigger downstream processing issues in systems that trust the Bubble data.

Content

Scanner excerpt · skill.py (reported line 284)May include surrounding context.

python
}
    
    try:
        resp = requests.post(url, headers=headers, json=data)
        resp.raise_for_status()
        print("Bubble registered successfully:", resp.json())
    except Exception as e:

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill explicitly states it uses X search tools and web sources, but the description does not warn users that their input category query may be sent to external services. This creates a privacy and transparency issue: users may unknowingly disclose sensitive interests or internal topics through third-party queries, especially if categories are customized beyond the provided examples.

Content

No source excerpt is available for this finding.