T09 · Insecure Skill Coding Practices
- Location
main.py:10- Finding
Hardcoded SkillPay API Credential Can Be Transmitted to a Configurable Network Endpoint
- Content
View full analysis
Vulnerability Details
File Location:
main.py:10-11, with credential transmission sinks atmain.py:203-218andmain.py:230-235
Vulnerability Type: Hardcoded secret and unsafe credential destination configuration
Risk Level: HighVulnerable Code
python SKILLPAY_API_KEY = os.getenv("SKILLPAY_API_KEY", "sk_8b36c2ca9e774eb0243752f907b086e78c8af866a4088d3e3475113ed446b71") SKILLPAY_API_BASE = os.getenv("SKILLPAY_API_BASE", "https://api.skillpay.me")The embedded credential is transmitted through the following functions:
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)python 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)Technical Analysis
The application contains a live-looking SkillPay bearer credential as the default value of
SKILLPAY_API_KEY. This contradicts the configuration inskill.yaml, which declares that environment variable as required. Anyone with access to the source package can recover and attempt to reuse the credential.The credential is included in the
Authorizationheader of requests ...[truncated 2343 chars]- Remediation
View remediation
Remediation Suggestions
- Revoke and rotate the exposed SkillPay credential immediately; source removal alone cannot invalidate copies already distributed.
- Remove the hardcoded fallback and require secret injection:
python SKILLPAY_API_KEY = os.getenv("SKILLPAY_API_KEY") if not SKILLPAY_API_KEY: raise RuntimeError("SKILLPAY_API_KEY is required") - Store the credential in a managed secret service or deployment secret facility rather than source control, images, or ordinary configuration files.
- Pin or allowlist the billing API origin. If custom endpoints are required for testing, permit them only in an explicit non-production mode.
- Require HTTPS and validate the parsed scheme and hostname before attaching the authorization header.
- Use a narrowly scoped provider credential that can perform only the charge operations required by this skill.
- Add automated secret scanning to commits and release artifacts.
- Avoid logging authorization headers, environment dumps, or complete outbound request objects.
- Establish periodic key rotation and monitoring for abnormal charge activity.
