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.
