T09 · Insecure Skill Coding Practices
- Location
scripts/billing_config.py:5- Finding
Hardcoded SkillPay Credential Enables Unauthorized Billing API Use
- Content
View full analysis
Vulnerability Details
File Location:
scripts/billing_config.py:5-8; credential loading and transmission occur atscripts/billing.py:11-15andscripts/billing.py:34-44
Vulnerability Type: Hardcoded secret and transmission of billing identity data to an external service
Risk Level: HighVulnerable Code
scripts/billing_config.py:5-8:python SKILLPAY_API_KEY = "sk_41b22ea52b5a803442973b84ec1cd8f395ed098a3890905f8a196a4ffdf43c87" SKILL_ID = "xanadu-social-manager" OWNER_WALLET = "0xF194917738617118dfff40E0542cea20Cf7dDC55" DEFAULT_PRICE = 0.001 # USDT per callscripts/billing.py:11-15:python # Load config try: from billing_config import SKILLPAY_API_KEY, SKILL_ID, DEFAULT_PRICE, OWNER_WALLET except ImportError: SKILLPAY_API_KEY = os.environ.get("SKILLPAY_API_KEY") SKILL_ID = "xanadu-social-manager" DEFAULT_PRICE = 0.001 OWNER_WALLET = Nonescripts/billing.py:34-44:python try: response = requests.post( f"{self.base_url}/charge", json={ "api_key": self.api_key, "skill_id": self.skill_id, "user_id": user_id, "amount": amount }, timeout=10 ) return response.json()Technical Analysis
A live-formatted SkillPay API key is embedded directly in a distributed source file. This contradicts the explicit instruction in
SKILL.mdnot to hardcode credentials. Becausebilling_config.pyis present, its import normally succeeds, causingSkillPayBillingto use the bundled credential and owner-controlled Skill ID unless the caller explicitly overrides them.The
charge()method then sends the API key, Skill ID, caller-supplied user identifier, and charge amount tohttps://api.skillpay.me/v1/charge. Billing is documented as optional and the method is not invoked automatically, so the network request is related to a declared ...[truncated 2384 chars]- Remediation
View remediation
Remediation Suggestions
- Revoke and rotate the exposed SkillPay API key immediately; assume that it has already been copied.
- Remove
SKILLPAY_API_KEY, the owner wallet, and owner-specific billing defaults from all distributed files and repository history. - Require the API key to be supplied explicitly through a deployment secret manager or protected environment variable. Fail closed when it is absent rather than silently selecting an owner credential.
- Require explicit, informed user or administrator consent before enabling billing or sending a user identifier to a third party.
- Use a conventional authorization header, such as
Authorization: Bearer ..., instead of placing the API key in the JSON body, subject to the SkillPay API specification. - Validate
user_idandamountlocally, enforce positive values and configured limits, and prevent callers from selecting arbitrary charge amounts unless that behavior is required. - Configure the external credential with the narrowest possible permissions, transaction limits, account restrictions, and rotation policy.
- Avoid logging request bodies or authorization headers and document the external recipient, transmitted fields, retention policy, and billing behavior.
- Replace broad exception handling with specific handling for timeouts, transport failures, non-success HTTP statuses, and invalid JSON. Call
response.raise_for_status()before accepting the response. - Add automated secret scanning and tests that reject committed API keys and verify that billing cannot operate without explicit deployment configuration.
