T09 · Insecure Skill Coding Practices
- Location
scripts/service.py:55- Finding
Locally Forgeable Payment Authorization
- Content
View full analysis
Vulnerability Details
File Location:
scripts/service.py:55-62, 81-90
Vulnerability Type: Payment authorization bypass through unverified local state
Risk Level: HighVulnerable Code
python def is_credential_valid(order_data: dict) -> bool: credential = order_data.get("payCredential") if not credential: return False credential_ts = order_data.get("credentialTimestamp") if credential_ts and time.time() - credential_ts > CREDENTIAL_TTL: return False return Truepython if not is_credential_valid(order_data): print("PAY_STATUS: ERROR") print("ERROR_INFO: No valid payment credential found. Complete payment via clawtip first.") sys.exit(1) pay_status = order_data.get("payStatus", "SUCCESS") print(f"PAY_STATUS: {pay_status}") if pay_status != "SUCCESS": print(f"ERROR_INFO: Payment status is '{pay_status}', cannot proceed") sys.exit(1)Technical Analysis
The authorization decision relies entirely on fields loaded from a locally writable JSON order file. A payment credential is considered valid whenever
payCredentialcontains any truthy value. The code does not verify a digital signature, message authentication code, issuer identity, or cryptographic binding between the credential and the order number, amount, payee, or Skill indicator.The credential timestamp is optional. If
credentialTimestampis absent, no expiration check occurs. A future timestamp also passes because the computed age is negative. In addition, a missingpayStatusis interpreted as"SUCCESS", which creates a fail-open authorization condition.Attack Path
- Run
scripts/create_order.pyto create a valid local order and obtain its order number. - Open the corresponding file under
~/.openclaw/skills/orders/{indicator}/{order_no}.json. - Add an arbitrary truthy field such as:
json { "payCredential": "f
...[truncated 907 chars]
- Run
- Remediation
View remediation
Remediation Suggestions
- Require a credential cryptographically signed by clawtip and verify it using a pinned, trusted public key.
- Bind the signed claims to the exact order number, amount, payee, Skill identifier, and indicator.
- Require explicit issued-at and expiration timestamps, validate their types, reject timestamps outside an acceptable clock-skew window, and reject credentials issued in the future.
- Require an explicit
payStatusvalue of"SUCCESS"; never default a missing status to success. - Reject absent, malformed, unsigned, expired, replayed, or incorrectly bound credentials.
- Where supported, verify the transaction identifier against an authoritative payment record and prevent reuse.
- Treat the local JSON document only as storage, not as a trusted source of authorization state.
