T09 · Insecure Skill Coding Practices
- Location
scripts/get_payment.py:44- Finding
WooshPay API Credential Disclosure Through an Attacker-Controlled Lookup URL
- Content
View full analysis
Vulnerability Details
File Location:
scripts/get_payment.py, lines 44–45 and 68–73
Vulnerability Type: Arbitrary authenticated request, credential disclosure, and server-side request forgery
Risk Level: HighVulnerable Code
python # 补全完整URL if not order_id.startswith("http"): if not order_id.startswith("pi_"): print("❌ 订单ID格式错误,应以 pi_ 开头") sys.exit(1) return order_idpython # 构建URL if order_id.startswith("http"): url = order_id else: url = f"{BASE_URL}/{order_id}" print(f"\n⏳ 正在查询订单 {order_id}...") try: response = requests.get(url, headers=headers, timeout=30)The
headersobject attached to this request contains the merchant credential:python headers = { "Authorization": f"Basic {api_key}" }Technical Analysis
The order lookup accepts any input beginning with
httpas a complete request URL. The script then sends a request to that URL while attaching theWOOSHPAY_API_KEYin an HTTP Basic Authorization header.There is no restriction requiring the destination to use HTTPS, no allowlist requiring the hostname to be
api.wooshpay.com, and no strict validation that the input is a payment intent ID. Consequently, a user can be induced to enter an attacker-controlled URL instead of an order ID.Because the Authorization header is attached before the destination is validated, the merchant API key is disclosed directly to the selected server. An
http://destination would additionally transmit it without transport encryption. The same behavior can access internal network addresses, creating an SSRF primitive.This behavior exceeds the minimum privileges required for payment status lookup. The declared functionality only requires requests to the fixed WooshPay endpoint.
Attack Path
- An attacker supplies a purported payment identifier such as
https://attacker.example/collect. - A merchant ...[truncated 1305 chars]
- An attacker supplies a purported payment identifier such as
- Remediation
View remediation
Remediation Suggestions
-
Accept only payment intent identifiers, not complete URLs.
-
Validate input with a strict, length-bounded allowlist expression such as
^pi_[A-Za-z0-9]+$. -
Always construct the request URL from the trusted constant:
python import re if not re.fullmatch(r"pi_[A-Za-z0-9]+", order_id): raise ValueError("Invalid payment intent ID") url = f"{BASE_URL}/{order_id}" response = requests.get(url, headers=headers, timeout=30) -
If configurable endpoints are required for testing, place them behind explicit configuration and verify that the parsed scheme is
httpsand the hostname exactly matches an approved allowlist. -
Never attach the API credential before validating the final destination.
-
Use a restricted API key with only read permission for status lookup if WooshPay supports scoped credentials.
-
Rotate the existing API key if the vulnerable lookup feature has been used with any untrusted URL.
-
