T09 · Insecure Skill Coding Practices
- Location
scripts/dhclip.py:681- Finding
Non-idempotent paid POST requests are automatically retried
- Content
View full analysis
Vulnerability Details
File Location:
scripts/dhclip.py, lines 681–707
Vulnerability Type: Automatic retry of non-idempotent paid operations
Risk Level: MediumVulnerable Code
python retry_status = {502, 503, 504} attempts = 3 if method.upper() == "GET" else 2 text = "" http_status = 0 last_err = "" for attempt in range(1, attempts + 1): try: with urllib.request.urlopen(req, timeout=timeout or self.timeout) as resp: text = resp.read().decode("utf-8", "replace") http_status = resp.status break except urllib.error.HTTPError as exc: text = exc.read().decode("utf-8", "replace") http_status = exc.code if exc.code in retry_status and attempt < attempts: last_err = "HTTP %s" % exc.code if self.verbose: sys.stderr.write("[dhclip] %s,%d/%d 重试\n" % (last_err, attempt, attempts)) time.sleep(1.5 * attempt) continue breakTechnical Analysis
The HTTP client retries every POST request once when it receives HTTP 502, 503, or 504. The same request object and body are submitted again without an idempotency key or reconciliation check.
The Skill uses POST requests to create paid image, speech, avatar, and video-generation tasks. A gateway failure is ambiguous: the upstream service may have accepted and created the first task before the gateway returned an error. Retrying that request can therefore create a second independently billable task.
The authorization boundary is the user's approval of one paid operation. An ambiguous response controlled by the remote API or gateway can cause the client to authorize another paid submission without a separate user decision.
Attack Path
- The user invokes a command that creates a paid task.
- The client sends the corresponding POST request to the configured API gateway.
- The upstream application accepts the task, but th ...[truncated 1081 chars]
- Remediation
View remediation
Remediation Suggestions
- Do not automatically retry non-idempotent paid POST requests unless the server provides an idempotency mechanism.
- Generate a cryptographically random idempotency key for each logical task and reuse that same key for all transport retries.
- Pass the key through the API's documented idempotency header or request field and require the server to return the original task for duplicate submissions.
- If idempotency is unavailable, return an “outcome unknown” error instead of resubmitting automatically.
- Where possible, reconcile the first submission using a client-generated operation identifier or a task-status endpoint before permitting another submission.
- Require explicit user confirmation before retrying a paid operation whose initial result is ambiguous.
- Add tests that simulate “request accepted, gateway returns 502” and verify that only one logical task is created.
