T05 · Unauthorized Access and Privilege Escalation
- Location
scripts/_return_refund_api_runner.py:258- Finding
Generic Authenticated Proxy Exceeds the Skill's Declared Read-Only Scope
- Content
View full analysis
Vulnerability Details
File Location:
scripts/_return_refund_api_runner.py:258-297, with the exposed entry point atscripts/return_refund_proxy.py:12-22and broad path validation atscripts/_shop_return_refund_common.py:106-124
Vulnerability Type: Excessive API capability and insufficient authorization boundary enforcement
Risk Level: MediumVulnerable Code
python # scripts/return_refund_proxy.py:12-22 def main() -> None: if len(sys.argv) < 2: print( "Usage: return_refund_proxy.py '<JSON>'\n" "Required: openId, path, method\n" "path whitelist: return_refund/, authorization/", file=sys.stderr, ) sys.exit(1) params = json.loads(sys.argv[1]) print(json.dumps(run_return_refund_proxy(params, "return_refund_proxy.py"), indent=2, ensure_ascii=False))python # scripts/_return_refund_api_runner.py:258-297 def run_return_refund_proxy(params: dict, caller: str = "return_refund_proxy.py") -> dict: """Generic proxy: path + method + openId (+ optional shop_cipher).""" if not params.get("skipDepCheck"): ensure_auth_skill_available(caller) path = params.get("path") method = params.get("method") if not path or not method: print("Missing required fields: path, method", file=sys.stderr) sys.exit(1) open_id = require_open_id(params) shop_cipher = None needs_cipher = str(path).lstrip("/").startswith("return_refund/") if needs_cipher: shop_cipher = resolve_shop_cipher(params, open_id) query_string = params.get("queryString") if shop_cipher: pairs = dict(parse_qsl(str(query_string or "").lstrip("?"), keep_blank_values=True)) pairs["shop_cipher"] = shop_cipher query_string = urlencode(pairs) body = params.get("body") if body is not None and not isinstance(body, str): body = json.dumps(body, ensure_ascii=False, separators=(",", ":")) ...[truncated 3868 chars]- Remediation
View remediation
Remediation Suggestions
- Remove
return_refund_proxy.pyfrom this read-only Skill unless generic forwarding is essential. - Replace namespace-prefix validation with an exact method-and-path allowlist:
GET authorization/202309/shopsGET return_refund/202309/reject_reasons
- Reject all methods other than
GETin the current Skill. - Route requests exclusively through
RETURN_REFUND_ENDPOINTSso callers cannot select arbitrary paths or methods. - If write operations are added later, implement each as a separate named API with:
- Exact path and method validation.
- A strict request schema.
- Rejection of undocumented body and query fields.
- Explicit user confirmation immediately before execution.
- Clear disclosure that the operation changes seller data.
- Enforce the same exact allowlist at the LinkFox gateway so client-side validation is not the sole security boundary.
- Add automated negative tests confirming that arbitrary paths and
POST,PUT,PATCH, andDELETEmethods are rejected.
- Remove
