T09 · Insecure Skill Coding Practices
Error
- Location
- main.py:10
- Finding
- Hard-Coded SkillPay Bearer Credential Exposed and Transmitted<![CDATA[ ## Vulnerability Details **File Location**: `main.py:10`, with network transmission at `main.py:200-235` **Vulnerability Type**: Hard-coded secret and insecure credential management **Risk Level**: High ### Vulnerable Code ```python SKILLPAY_API_KEY = os.getenv("SKILLPAY_API_KEY", "sk_8b36c2ca9e774eb0243752f907b086e78c8af866a4088d3e3475113ed446b71") ``` The embedded credential is subsequently placed in authorization headers and transmitted to the configured SkillPay API: ```python def create_skillpay_charge(amount: str, currency: str) -> Tuple[str, str]: if not SKILLPAY_API_KEY: raise HTTPException(status_code=400, detail="Missing SKILLPAY_API_KEY") url = f"{SKILLPAY_API_BASE.rstrip('/')}/v1/charges" headers = { "Authorization": f"Bearer {SKILLPAY_API_KEY}", "Content-Type": "application/json", } body = { "amount": amount, "currency": currency, "title": "OpenClaw Skill Payment", "description": "Polymarket Movers x3", } r = requests.post(url, json=body, headers=headers, timeout=20) if r.status_code not in (200, 201): raise HTTPException(status_code=502, detail="SkillPay create charge failed") data = r.json() cid = str(data.get("id") or data.get("charge_id") or "") purl = data.get("payment_url") if not purl and cid: purl = f"{SKILLPAY_WEB_BASE.rstrip('/')}/checkout/{cid}" if not cid or not purl: raise HTTPException(status_code=502, detail="Invalid SkillPay response") return cid, purl def get_skillpay_status(charge_id: str) -> str: if not SKILLPAY_API_KEY: raise HTTPException(status_code=400, detail="Missing SKILLPAY_API_KEY") url = f"{SKILLPAY_API_BASE.rstrip('/')}/v1/charges/{charge_id}" headers = {"Authorization": f"Bearer {SKILLPAY_API_KEY}"} r = requests.get(url, headers=headers, timeout=20) if r.status_code != 200: raise HTTPException(status_code=502, detail="SkillPay status q ...[truncated 2356 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Revoke and rotate the exposed SkillPay credential immediately. 2. Remove the hard-coded fallback and require secret injection: ```python SKILLPAY_API_KEY = os.getenv("SKILLPAY_API_KEY") if not SKILLPAY_API_KEY: raise RuntimeError("SKILLPAY_API_KEY must be configured securely") ``` 3. Store the replacement credential in a deployment secret manager rather than source control, package files, images, logs, or general configuration. 4. Use a dedicated, minimally scoped API credential limited to the required charge-creation and status-query operations. 5. Restrict or validate `SKILLPAY_API_BASE` against an explicit HTTPS host allowlist before attaching authorization headers. 6. Review repository history, build artifacts, deployment images, and SkillPay audit logs for exposure or unauthorized use. 7. Add automated secret scanning to development and release pipelines and block publication when credential-like values are detected. ]]>
