T09 · Insecure Skill Coding Practices
Error
- Location
- paygate.py:252
- Finding
- Unsigned Payment Receipts Can Be Embedded as Valid Certifications<![CDATA[ ## Vulnerability Details **File Location**: `paygate.py:252-260` **Vulnerability Type**: Missing cryptographic verification before certification **Risk Level**: High ### Vulnerable Code ```python if args.cmd == "embed": report = json.loads(Path(args.report).read_text(encoding="utf-8")) data = json.loads(Path(args.receipt).read_text(encoding="utf-8")) receipt = data.get("receipt", data) sig = data.get("receipt_signature", "") certified = embed_certification(report, receipt, sig) Path(args.out).write_text(json.dumps(certified, ensure_ascii=False, indent=2), encoding="utf-8") print(f"已认证报告写 {args.out}") return 0 ``` The called function marks the report as paid without performing verification: ```python def embed_certification(report: dict, receipt: dict, signature_b64: str) -> dict: """把已验证的付款认证块并入审计报告(报告本体仍是 audit.py 离线产出)。""" certified = dict(report) certified["certification"] = { "paid": True, "oracle": receipt.get("oracle"), "out_trade_no": receipt.get("out_trade_no"), "trade_no": receipt.get("trade_no"), "amount": receipt.get("amount"), "goods_name": receipt.get("goods_name"), "fulfilled_at": receipt.get("fulfilled_at"), "receipt_signature": signature_b64, "verified_offline_with": "embedded_server_pubkey", } return certified ``` ### Technical Analysis The `embed` command treats the receipt file and signature as trusted input. It never calls `verify_receipt()` before passing the data to `embed_certification()`. That function unconditionally adds `"paid": True` and `"verified_offline_with": "embedded_server_pubkey"` to the output. Consequently, neither a valid RSA signature nor evidence of payment is required to create an apparently certified report. The presence of a separate `verify` command does not establish a security boundary because users can invoke `embed` directly, and there is no st ...[truncated 2498 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Make receipt verification mandatory inside the `embed` command: ```python pub = load_pubkey() if not verify_receipt(receipt, sig, pub): print("error: invalid receipt signature", file=sys.stderr) return 1 certified = embed_certification(report, receipt, sig) ``` 2. Do not rely on a separately invoked `verify` command. Verification and embedding must be one atomic, fail-closed operation. 3. Validate all signed receipt semantics after signature verification: - Expected oracle identity. - Expected currency and exact amount. - Expected product or service identifier. - Nonempty transaction and order identifiers. - Fulfillment timestamp and acceptable validity period. 4. Bind the receipt to the specific report by including the report's SHA-256 digest in the server-signed receipt. Refuse certification unless that digest exactly matches the report being embedded. 5. Add replay protection by signing a unique audit identifier and recording whether the receipt has already been used, where reuse is not intended. 6. Set certification metadata only after all cryptographic and semantic checks pass. Do not state `"verified_offline_with"` based merely on the selected code path. 7. If full report contents are intended to remain paid, do not write plaintext `full.md` or `full.json` before authorization. Store only the preview, or encrypt the full output using a key released after successful receipt validation. 8. Add regression tests proving that missing, malformed, forged, mismatched, and replayed receipts cannot produce certified output. ]]>
