T05 · Unauthorized Access and Privilege Escalation
Error
- Location
- src/payment_skill.py:220
- Finding
- Refund operations do not enforce the declared approval requirement<![CDATA[ ## Vulnerability Details **File Location**: `src/payment_skill.yaml:50-55`, `src/payment_skill.py:220-247`, `skill_cli.py:203-210` **Vulnerability Type**: Missing authorization and approval enforcement **Risk Level**: High ### Vulnerable Code ```yaml - name: refund_payment description: 发起退款 timeout: 10000 rate_limit: requests_per_minute: 30 requires_approval: true ``` ```python async def refund_payment(self, transaction_id: str, amount: float = None) -> Dict[str, Any]: try: logger.info(f"发起退款: {transaction_id}, 金额: {amount}") if not transaction_id: raise ValueError("交易 ID 不能为空") if amount is not None and amount <= 0: raise ValueError("退款金额必须大于 0") result = await self.api_client.refund_payment( transaction_id=transaction_id, amount=amount ) ``` ```python elif args.command == 'refund_payment': params = { 'transaction_id': args.transaction_id } if args.amount: params['amount'] = args.amount if args.reason: params['reason'] = args.reason ``` ### Technical Analysis The Skill manifest explicitly marks `refund_payment` as requiring approval, but this requirement is not enforced in the runtime implementation. The refund method validates only that a transaction identifier exists and that an optional amount is positive. It does not require an approval token, authenticated user confirmation, authorization context, or other proof that the refund was approved. The CLI also invokes the same runtime path directly. Therefore, the manifest attribute is only descriptive and does not create an effective security boundary. Authorization must be enforced at the point where the financial action is performed, rather than relying on metadata or an external caller to behave correctly. ### Attack Path 1. An attacker, compromised Agent, or unauthorized process gains permission to execute the Skill CLI ...[truncated 1013 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions - Enforce approval in executable runtime code before calling the payment API. - Require a short-lived, cryptographically verifiable approval token bound to: - The authenticated user or operator. - The transaction identifier. - The exact refund amount. - An expiration time. - A unique nonce to prevent replay. - Reject full or partial refunds when the approval token is absent, expired, replayed, or does not match the request. - Enforce the same authorization rule on the payment server; client-side checks must not be the only control. - Apply least-privilege credentials so the Skill cannot issue refunds unless explicitly required. - Record the approving identity, transaction, amount, timestamp, and authorization result in a tamper-resistant audit log. - Add tests that invoke the CLI and `PaymentSkill.execute()` directly and verify that unapproved refunds are denied. ]]>
