Back to skill

Security audit

SkillPay

Security checks for vulnerabilities and agentic risk

Overview

This skill is a disclosed payment integration, but it asks users and skill code to handle reusable payment credentials without enough scoping or warnings.

Review this carefully before installing or using it. Treat `sp_usr_...` and `sp_bld_...` values as sensitive bearer secrets, do not pass reusable account keys to untrusted skills, and avoid running deposit, withdrawal, or payment commands unless you have verified the amount, account, destination wallet, and revocation options.

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
SKILL.md:68
Finding
Reusable Buyer API Key Is Exposed to Untrusted Skill Code## Vulnerability Details **File Location**: `SKILL.md`, lines 68-79 **Vulnerability Type**: Reusable payment credential exposure **Risk Level**: High ### Vulnerable Code ```python import requests def charge_user(user_key, skill_slug="my-skill"): resp = requests.post("https://skillpay.gpupulse.dev/api/v1/pay", json={ "user_key": user_key, "skill_slug": skill_slug }) if resp.status_code == 200: return True # paid, execute skill elif resp.status_code == 402: return False # insufficient credits return False ``` ### Technical Analysis The documented integration requires a buyer's reusable `sp_usr_...` API key to be provided directly to skill code. The skill then transmits that credential in the JSON body of a payment request. This design violates least privilege because an untrusted or compromised skill receives the underlying account credential instead of a narrowly scoped payment authorization. The same buyer key is also documented as a bearer credential for user account endpoints elsewhere in `SKILL.md`. No transaction-specific amount, expiration, nonce, user confirmation, or cryptographic binding between the authorization and a particular invocation is shown. Because the skill receives the raw credential, it can copy, log, retain, or disclose it. The code also does not demonstrate replay protection or a mechanism restricting the credential to one payment for one expected skill invocation. Although server-side protections may exist, none are documented in the audited project. ### Attack Path 1. A buyer registers with SkillPay and receives a reusable `sp_usr_...` API key. 2. The buyer invokes a paid skill and supplies that key as the documented `user_key` argument. 3. A malicious skill, compromised skill, dependency, or logging system captures the raw key. 4. The attacker retains the key after the legitimate invocation has completed. 5. The attacker ...[truncated 965 chars]
Remediation
## Remediation Suggestions - Do not provide the reusable account API key to third-party skill code. - Introduce short-lived, single-use payment authorization tokens issued directly to the buyer. - Bind each token cryptographically and server-side to the expected buyer, skill slug, exact amount, invocation identifier, and expiration time. - Add a unique nonce and reject all replay attempts after the first successful redemption. - Require explicit buyer approval when creating the payment authorization rather than allowing a skill to choose transaction parameters using an account credential. - Separate account-management credentials from payment credentials and ensure payment tokens cannot access balance, deposit, registration, or withdrawal endpoints. - Enforce server-side spending limits, rate limits, anomaly detection, revocation, and transaction notifications. - Avoid logging credentials and redact authorization values and payment tokens from application telemetry. - Provide credential rotation and immediate revocation mechanisms for exposed keys. - Update the example integration so the skill receives only a scoped authorization token and never handles the buyer's reusable API key.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
Findings (5)

External Transmission

Medium
Category
Data Exfiltration
Content
### Register
```bash
curl -X POST "$BASE/user/register" \
  -H "Content-Type: application/json" \
  -d '{"name": "my-agent", "email": "optional@email.com"}'
```
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill instructs users to obtain and use `sp_usr_...` API keys in Authorization headers but never warns that these are sensitive bearer credentials. Anyone who obtains such a key can likely act as that user against the payment API, potentially spending credits or accessing account data. In a payment-related skill, omission of credential-handling guidance is more dangerous than in a generic integration guide because the tokens authorize financially relevant actions.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The deposit and withdrawal examples describe actions that move funds or credits but provide no warning that these operations may have financial or irreversible consequences. Users may execute commands without understanding they are spending money, consuming balances, or triggering withdrawals tied to real USDC value. Because this skill is specifically designed for monetization and payouts, missing transactional warnings materially increases the risk of accidental financial loss.

External Transmission

Medium
Category
Data Exfiltration
Content
import requests

def charge_user(user_key, skill_slug="my-skill"):
    resp = requests.post("https://skillpay.gpupulse.dev/api/v1/pay", json={
        "user_key": user_key,
        "skill_slug": skill_slug
    })
Confidence
88% confidence
Finding
This duplicate finding points to the same `requests.post` call that sends billing data to `https://skillpay.gpupulse.dev/api/v1/pay`. The behavior is not inherently malicious, but it is a true security concern because the sample normalizes sending sensitive payment credentials to an external service without warning about secrecy, auditability, or financial implications. The payment context makes mishandling more impactful than ordinary telemetry or non-sensitive API calls.

External Transmission

Medium
Category
Data Exfiltration
Content
import requests

def charge_user(user_key, skill_slug="my-skill"):
    resp = requests.post("https://skillpay.gpupulse.dev/api/v1/pay", json={
        "user_key": user_key,
        "skill_slug": skill_slug
    })
Confidence
88% confidence
Finding
This duplicate finding points to the same `requests.post` call that sends billing data to `https://skillpay.gpupulse.dev/api/v1/pay`. The behavior is not inherently malicious, but it is a true security concern because the sample normalizes sending sensitive payment credentials to an external service without warning about secrecy, auditability, or financial implications. The payment context makes mishandling more impactful than ordinary telemetry or non-sensitive API calls.

Static analysis

No suspicious patterns detected.