Back to skill

Security audit

x402 Layer

Security checks for vulnerabilities and agentic risk

Overview

The skill has a coherent purpose, but its signing tools can authorize excessive payments or unintended wallet transactions without sufficient checks.

Start with secret-free discovery. Avoid unattended direct-key payments, registration or staking until spending limits and transaction validation are enforced. Use a dedicated low-balance wallet, task-specific credentials and approved HTTPS hosts. Keep downloads in an empty dedicated directory. Before using webhooks to grant goods or credits, add freshness checks and duplicate-event protection.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/pay_base.py
Finding

Remote Base payment quotes become unrestricted spending authorizations

Content
View full analysis

Impact

The endpoint receives a valid Base USDC TransferWithAuthorization for its chosen amount and recipient. It can redeem that authorization subject to wallet balance and contract checks. The signer defaults to a one-hour validity period.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/solana_signing.py
Finding

Solana USDC payment flow permits endpoint-selected assets and amounts

Content
View full analysis

Impact

A malicious endpoint can obtain a signed transfer of another compatible six-decimal SPL token held by the wallet, or an excessive amount, rather than the intended USDC purchase. Success depends on valid token accounts, balances and chain checks.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/stake_sgl.py
Finding

Staking helper signs remote transactions without validating staking intent

Content
View full analysis

Impact

The response provider can obtain and submit wallet-signed transfers or other state changes unrelated to the requested staking action, subject to required signers, balances and chain validation.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/register_agent.py
Finding

EVM registration and updates execute API-selected contract calls

Content
View full analysis

Impact

A malicious response can cause a token transfer, approval or other wallet-authorized contract call instead of registration or URI update. The client signs and broadcasts the call automatically. Impact depends on wallet holdings and the selected contract's authorization rules.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/solana_signing.py
Finding

Solana registration and updates blindly sign prepared messages

Content
View full analysis

Impact

The client can sign and broadcast transfers or other wallet-authorized state changes unrelated to agent registration or metadata updates. For registration, an attacker can construct a message requiring both the wallet and the generated asset signer.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/verify_webhook_payment.py
Finding

Webhook verification accepts replayed signed payment events

Content
View full analysis

Impact

The verifier repeatedly returns success for the same signed event. A fulfillment integration using that success as authorization can grant duplicate credits, settlement or delivery unless it separately enforces idempotency.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/consume_product.py
Finding

Product downloads can overwrite unrelated working-directory files

Content
View full analysis

Impact

A response naming an existing configuration, source or document file can overwrite it with remote bytes. Existing symbolic links are also followed, potentially affecting a target outside the working directory. No automatic execution of the downloaded content was established.

Vulnerability Patterns
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (137)

Tainted flow: 'wallet' from os.getenv (line 38, 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 · scripts/check_credits.py (reported line 44)May include surrounding context.

python
print(f"Checking credits for: {endpoint_slug}")
    print(f"Wallet: {wallet}")

    response = requests.get(
        url,
        params={"action": "balance", "wallet": wallet},
        headers={"Accept": "application/json"},

Tainted flow: 'payment_payload' from os.getenv (line 253, credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Confidence
97% confidence
Finding

The private key is used locally rather than transmitted, and sending a payment signature is expected in this purchasing skill. However, the script signs the server-supplied recipient and amount without an independently approved price or spending limit, allowing a malicious or compromised payment response to obtain a redeemable USDC authorization exceeding the user's intended purchase.

Content

Scanner excerpt · scripts/consume_product.py (reported line 273)May include surrounding context.

python
# Step 4: Make request with payment
    print("\nStep 3: Submitting payment and requesting download...")
    
    response = requests.get(
        api_url,
        headers={
            "X-Payment": json.dumps(payment_payload),

Tainted flow: 'url' from os.getenv (line 64, 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 · scripts/erc8004_wallet_client.py (reported line 29)May include surrounding context.

python
headers: Optional[Dict[str, str]] = None,
    timeout: int = 60,
) -> Dict[str, Any]:
    response = requests.post(url, json=body, headers=headers or {}, timeout=timeout)
    try:
        data = response.json()
    except Exception:

Tainted flow: 'headers' from os.getenv (line 51, 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 · scripts/list_on_marketplace.py (reported line 80)May include surrounding context.

python
if banner_url:
        print(f"  Banner: {banner_url}")

    response = requests.post(url, json=data, headers=headers)

    if response.status_code in [200, 201]:
        result = response.json()

Tainted flow: 'headers' from os.getenv (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 · scripts/list_on_marketplace.py (reported line 104)May include surrounding context.

python
print(f"Unlisting endpoint: {slug} from marketplace...")

    response = requests.post(url, json=data, headers=headers)

    if response.status_code == 200:
        result = response.json()

Tainted flow: 'api_key' from os.getenv (line 233, 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 · scripts/manage_endpoint.py (reported line 45)May include surrounding context.

python
def get_endpoint_info(slug: str, api_key: Optional[str] = None) -> dict:
    response = requests.get(
        f"{API_BASE}/agent/endpoints",
        params={"slug": slug},
        headers=_build_headers(api_key),

Tainted flow: 'endpoint_id' from os.getenv (line 88, 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 · scripts/manage_endpoint.py (reported line 99)May include surrounding context.

python
"details": details,
        }

    response = requests.get(
        f"{API_BASE}/agent/endpoints",
        params={"action": "stats", "endpoint_ids": endpoint_id},
        headers={"Accept": "application/json"},

Tainted flow: 'api_key' from os.getenv (line 161, credential/environment) → requests.patch (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 · scripts/manage_endpoint.py (reported line 165)May include surrounding context.

python
if not api_key:
        return {"error": "Update requires X_API_KEY or API_KEY"}

    response = requests.patch(
        f"{API_BASE}/agent/endpoints",
        params={"slug": slug},
        headers={**_build_headers(api_key), "Content-Type": "application/json"},

Tainted flow: 'api_key' from os.getenv (line 52, credential/environment) → requests.patch (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 · scripts/manage_webhook.py (reported line 53)May include surrounding context.

python
def set_webhook(slug: str, webhook_url: str) -> dict:
    """Set or update the webhook URL for an endpoint."""
    api_key = _load_api_key()
    response = requests.patch(
        f"{API_BASE}/agent/endpoints",
        params={"slug": slug},
        json={"webhook_url": webhook_url},

Tainted flow: 'api_key' from os.getenv (line 73, credential/environment) → requests.patch (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 · scripts/manage_webhook.py (reported line 74)May include surrounding context.

python
def remove_webhook(slug: str) -> dict:
    """Remove the webhook URL from an endpoint."""
    api_key = _load_api_key()
    response = requests.patch(
        f"{API_BASE}/agent/endpoints",
        params={"slug": slug},
        json={"webhook_url": None},

Tainted flow: 'api_key' from os.getenv (line 88, 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 · scripts/manage_webhook.py (reported line 89)May include surrounding context.

python
def get_webhook_info(slug: str) -> dict:
    """Check if an endpoint has a webhook configured."""
    api_key = _load_api_key()
    response = requests.get(
        f"{API_BASE}/agent/endpoints",
        params={"slug": slug},
        headers={"X-API-Key": api_key, "Accept": "application/json"},

Tainted flow: 'signed_tx_base64' from os.getenv (line 223, 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 · scripts/solana_signing.py (reported line 225)May include surrounding context.

python
signed_tx = VersionedTransaction(raw_tx.message, [keypair, *(extra_signers or [])])
    signed_tx_base64 = base64.b64encode(bytes(signed_tx)).decode()

    response = requests.post(
        rpc_url,
        json={
            "jsonrpc": "2.0",

Tainted flow: 'BASE' from os.getenv (line 38, 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 · scripts/stake_sgl.py (reported line 87)May include surrounding context.

python
# ─── API helpers ─────────────────────────────────────────────────────────────

def _get(path: str) -> dict:
    r = requests.get(f"{BASE}{path}", timeout=TIMEOUT)
    data = r.json()
    if not r.ok:
        sys.exit(f"GET {path} failed ({r.status_code}): {data.get('error', data)}")

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

Critical
Category
Data Flow
Confidence
98% confidence
Finding

The dangerous flow is not disclosure of the BASE environment variable: _prepare_sign_submit blindly signs every transaction returned by the configured server and sends the signed transactions back. A compromised staking service or malicious endpoint override could supply transfers or authority-changing instructions unrelated to the requested staking action, potentially draining assets controlled by the wallet; the printed warning does not validate transaction contents.

Content

Scanner excerpt · scripts/stake_sgl.py (reported line 95)May include surrounding context.

python
def _post(path: str, body: dict) -> dict:
    r = requests.post(f"{BASE}{path}", json=body, timeout=TIMEOUT)
    data = r.json()
    if not r.ok:
        msg = data.get("error", data)

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

Critical
Category
Data Flow
Confidence
90% confidence
Finding

X402_API_BASE can select an arbitrary destination, including an unencrypted HTTP URL, and the script sends the worker API key there without validating the scheme or host. If an attacker can influence this configuration, the key and feedback contents can be disclosed; the reputation-writing context makes unauthorized use of the key consequential, although this requires configuration influence and is not evidence of intentional exfiltration.

Content

Scanner excerpt · scripts/submit_feedback.py (reported line 59)May include surrounding context.

python
else:
        body["agentId"] = agent_id

    response = requests.post(
        url,
        json=body,
        headers={

Tainted flow: 'STUDIO_BASE' from os.getenv (line 25, 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 · scripts/support_threads.py (reported line 68)May include surrounding context.

python
def _resolve_listing(listing_type: str, listing_ref: str) -> Dict[str, str]:
    if listing_type == "endpoint" and not listing_ref.startswith("http") and len(listing_ref) < 64:
        response = requests.get(f"{STUDIO_BASE}/api/public/endpoints/{listing_ref}", timeout=30)
        if response.status_code == 200:
            data = response.json()
            return {"listing_id": data["id"], "listing_type": "endpoint", "name": data.get("name") or listing_ref}

Tainted flow: 'STUDIO_BASE' from os.getenv (line 25, 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 · scripts/support_threads.py (reported line 76)May include surrounding context.

python
if listing_ref.startswith("http"):
        slug = listing_ref.rstrip("/").split("/")[-1]
        if listing_type == "endpoint":
            response = requests.get(f"{STUDIO_BASE}/api/public/endpoints/{slug}", timeout=30)
            if response.status_code == 200:
                data = response.json()
                return {"listing_id": data["id"], "listing_type": "endpoint", "name": data.get("name") or slug}

Tainted flow: 'API_BASE' from os.getenv (line 24, 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 · scripts/support_threads.py (reported line 82)May include surrounding context.

python
return {"listing_id": data["id"], "listing_type": "endpoint", "name": data.get("name") or slug}

    # fallback to marketplace search by id/slug
    response = requests.get(f"{API_BASE}/api/marketplace", params={"search": listing_ref, "limit": 50}, timeout=30)
    response.raise_for_status()
    data = response.json()
    listings = data.get("listings", [])

Tainted flow: 'api_key' from os.getenv (line 46, credential/environment) → requests.put (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 · scripts/topup_endpoint.py (reported line 68)May include surrounding context.

python
headers=headers,
        )

    response = requests.put(
        url,
        params=params,
        json=data,

Tainted flow: 'api_key' from os.getenv (line 46, credential/environment) → requests.put (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 · scripts/topup_endpoint.py (reported line 100)May include surrounding context.

python
except Exception as exc:
        return {"error": f"Failed to build {selected_network} payment: {exc}"}

    response = requests.put(
        url,
        params=params,
        json=data,

Description-Behavior Mismatch

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

Endpoint management is consistent with the declared purpose, and authenticated updates and deletion are expected. However, main() loads an API key for every command, and get_endpoint_info() transmits it whenever available. Consequently, list, info, and the endpoint lookup within stats use credentials even though they perform no signing or owner-scoped writes. This conflicts with the description's explicit credential-use restriction. Read-only requests can proceed without a key, but automatic credential use when one is present is not gated as declared. No unrelated network destination or additional undeclared primary purpose is evident.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding

Campaign management is not declared among the supported capabilities. The shown commands operate on campaigns rather than API endpoints, credits, webhooks, marketplace listings, agent identities, or staking positions. The dashboard credential is consistent with the declared optional authentication methods, but that does not establish campaign management as a declared capability. The script implementation is not supplied, so this assessment is limited to the operations exposed by the shown commands.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
MCP Tool Poisoning
Confidence
90% confidence
Finding

Fundraiser campaign management is the code's primary purpose, but it is not identified in the declared capabilities. Although the description broadly mentions credentialed Singularity operations, fundraising is materially distinct from managing monetized API endpoints, agent identities, or staking. The authentication mechanism and service domain are consistent with the description; the mismatch is the undeclared campaign-management functionality, not suspicious credential handling or direct on-chain transfers.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
MCP Tool Poisoning
Confidence
88% confidence
Finding

Endpoint information retrieval and credentialed owner operations are consistent with the description. However, campaign management is a distinct exposed capability that is not described or visibly connected to the declared endpoint, payment, identity, or staking workflows. The supplied chunk shows script invocations only; it does not establish their internal implementation or any actual movement of funds.

Content

No source excerpt is available for this finding.

Incomplete referenced artifact analysis

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
`ows_cli.py` | `references/pay-per-request.md`, `references/credit-based.md`, `references/agentkit-benefits.md`, `references/openwallet-ows.md` |