Back to skill

Security audit

clawauto-shop

Security checks for vulnerabilities and agentic risk

Overview

This skill is review-worthy because it can create real food orders, sends account credentials to configurable backends, and stores sensitive order links locally.

Install only if you trust the configured backend. Use HTTPS for any non-local backend, use a scoped or test API key where possible, keep --allow-final-submit off until the user explicitly confirms the purchase, and protect or delete outputs/openclaw_order_state because they may contain usable order links, pickup codes, and screenshots.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T09 · Insecure Skill Coding Practices

Error
Location
openclaw_skill.py:128
Finding
API credentials and personal identifiers may be transmitted over plaintext HTTP## Vulnerability Details **File Location**: `openclaw_skill.py:128-132` (also affects requests at lines 145-159, 177-185, and 203-227); insecure configuration is documented at `OPENCLAW_INSTALL_CHECKLIST.md:20-22` **Vulnerability Type**: Transmission of sensitive information over an unencrypted channel **Risk Level**: High ### Vulnerable Code ```python def get_products(identity: str, api_key: str, base_url: str, timeout: int = 10) -> dict: payload = {"username": identity, "phone": identity, "api_key": api_key} url = f"{base_url}/products" try: response = requests.post(url, json=payload, timeout=timeout) ``` The same credential-bearing request pattern is used for order status, order history, and order creation: ```python payload = { "username": identity, "phone": identity, "api_key": api_key, "order_id": int(order_id), } url = f"{base_url.rstrip('/')}/order/status" response = requests.post(url, json=payload, timeout=timeout) ``` The installation checklist permits a remote plaintext HTTP endpoint: ```env KFC_PLATFORM_PHONE=your_platform_phone KFC_PLATFORM_API_KEY=your_platform_api_key KFC_PLATFORM_BASE_URL=http://your-backend-host:8888/api/openclaw ``` ### Technical Analysis Sending an identity and API key to the ordering backend is necessary for the Skill's declared functionality. However, accepting and documenting non-loopback HTTP endpoints exceeds the minimum safe network privilege needed for that functionality. `resolve_base_url()` and the request functions do not enforce HTTPS for remote endpoints. When an operator configures an `http://` backend, `requests.post()` transmits the phone number or username and reusable API key without transport encryption. Request timeouts do not provide confidentiality or server authentication. Placing the API key in the JSON body also increases the chance that it will be captured by application request logging, revers ...[truncated 1468 chars]
Remediation
## Remediation Suggestions 1. Reject non-HTTPS URLs unless the destination is explicitly verified as loopback: ```python import ipaddress from urllib.parse import urlparse def validate_base_url(base_url: str) -> str: parsed = urlparse(base_url) host = parsed.hostname or "" is_loopback = host == "localhost" try: is_loopback = is_loopback or ipaddress.ip_address(host).is_loopback except ValueError: pass if parsed.scheme != "https" and not is_loopback: raise ValueError("Remote backend URLs must use HTTPS") return base_url.rstrip("/") ``` 2. Apply validation centrally in `resolve_base_url()` so every endpoint inherits the policy. 3. Replace the remote HTTP example in `OPENCLAW_INSTALL_CHECKLIST.md` with an HTTPS URL. Clearly state that HTTP is allowed only for loopback development. 4. Prefer a scoped, short-lived authorization token in the `Authorization` header rather than placing reusable secrets in request bodies. 5. Configure the backend and reverse proxies to redact authorization data and request bodies from logs. 6. Use separate read-only and order-creation scopes so compromise of a listing credential cannot authorize purchases. 7. Ensure TLS certificate verification remains enabled and do not introduce a `verify=False` bypass.

T09 · Insecure Skill Coding Practices

Warning
Location
openclaw_skill.py:258
Finding
Sensitive order links, pickup data, and screenshots are stored without explicit access restrictions or retention controls## Vulnerability Details **File Location**: `openclaw_skill.py:258-292`; related artifact creation occurs in `kfc_custom_product_flow.py:95-96, 154-155, 183`, `kfc_place_order_test_old.py:140-141, 200-201, 246-247, 323-324, 354`, `kfc_vip_choose_spec_flow.py:168-169, 227-228, 256`, `mcd_custom_product_flow.py:85-86, 150-151, 190`, and `mcd_place_order_test.py:127-128, 184-185, 199-200, 215-216, 250` **Vulnerability Type**: Insecure local storage of sensitive order artifacts **Risk Level**: Medium ### Vulnerable Code The local state includes redemption URLs, order identifiers, idempotency keys, pickup results, and account-related order metadata: ```python payload = { "idempotency_key": idempotency_key, "order_id": order_id or (order_resp or {}).get("order_id") or 0, "url": url or (order_resp or {}).get("url") or "", "stage": stage, "flow_code": flow_code, "flow_result": flow_result, "updated_at": now, } if order_resp: payload["cost_yuan"] = order_resp.get("cost_yuan", order_resp.get("points_cost")) payload["balance_yuan"] = order_resp.get("balance_yuan", order_resp.get("points_balance")) payload["product_name"] = (order_resp.get("product") or {}).get("name") if "created_at" not in payload: payload["created_at"] = now path = state_dir / f"{_sanitize_idem_key(idempotency_key)}.json" try: # Preserve created_at if the file already exists. if path.exists(): try: existing = json.loads(path.read_text(encoding="utf-8")) payload["created_at"] = existing.get("created_at", now) except Exception: pass path.write_text(json.dumps(payload, ensure_ascii=False, indent=2), encoding="utf-8") return path except OSError: return None ``` Browser-flow scripts also persist full-page screenshots and result JSON. For example: ```python shot1 = out_dir / f"kfc_cp_step1_pickup_{tag}.png" await p ...[truncated 3186 chars]
Remediation
## Remediation Suggestions 1. Create sensitive directories with owner-only permissions: ```python state_dir.mkdir(parents=True, exist_ok=True, mode=0o700) os.chmod(state_dir, 0o700) ``` 2. Create files atomically with mode `0600`, rather than relying on `Path.write_text()` and the ambient umask: ```python flags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC fd = os.open(path, flags, 0o600) with os.fdopen(fd, "w", encoding="utf-8") as handle: json.dump(payload, handle, ensure_ascii=False, indent=2) ``` 3. Write to an owner-only temporary file and atomically rename it to avoid partially written state and symlink-related replacement risks. 4. Store a redacted URL by default. Remove or encrypt query values such as `cdkey` and `outId` unless recovery strictly requires them. 5. Make screenshots opt-in and warn that they may contain sensitive order information. 6. Add configurable retention and automatically delete state, result files, and screenshots after a short period or once the order completes. 7. Add and verify a `.gitignore` covering `outputs/`, `openclaw_order_state/`, `.env`, screenshots, and result JSON, while recognizing that ignore rules are not a substitute for filesystem permissions. 8. Avoid printing complete sensitive URLs to shared logs. If the recovery protocol requires the URL on standard output, provide an explicit secure-output mode and redact it in ordinary diagnostic logging. 9. Consider encrypting recovery state with a user-specific secret when artifacts must persist across sessions.
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (32)

Credential Access

High
Category
Privilege Escalation
Content
- Can run with user-configured phone + api key.

## Required Runtime Config
Use either CLI args or environment variables. For OpenClaw usage, **.env is recommended**:

### Env-based config (dev / prod)
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Intent-Code Divergence

High
Confidence
97% confidence
Finding
This script is presented as a 'flow tester' but its default behavior can progress through the real KFC ordering flow and submit a live order unless the operator explicitly passes --no-submit. In an agent/skill context, that mismatch between description and behavior is dangerous because it can trigger unintended real-world transactions, purchases, or operational actions during testing or routine execution.

Missing User Warnings

High
Confidence
97% confidence
Finding
The script proceeds from page navigation to clicking '下单' and then a final confirmation button, which can place a real order unless the operator explicitly remembers to pass --no-submit. In an automation/agent context, that creates a dangerous side effect: a supplied URL and store code are enough to trigger a purchase flow without an in-band user confirmation, preview, or explicit acknowledgment of cost/commitment.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The checklist instructs operators to configure real platform credentials and a live backend endpoint but does not warn that these secrets enable access to production ordering functions. In the context of a food-ordering automation skill, this increases the chance of accidental use of real accounts, unintended transactions, and credential mishandling during setup or testing.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The real-order validation section provides runnable commands that drive browser automation through live KFC and McD ordering flows, yet it does not clearly warn that these actions may interact with real stores, consume points, reserve inventory, or place orders if safeguards fail. Because the skill is specifically designed for transaction automation, the missing warning materially raises the risk of accidental real-world impact during testing.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
The user-facing instructions at this line are written as a mandatory directive in Chinese, and the document continues to present operational guidance in Chinese without indicating multilingual support or giving the user a language preference option. This creates a locale/language policy concern because the skill appears to require a specific language by default rather than offering user choice.

Ssd 3

Medium
Confidence
95% confidence
Finding
The skill explicitly instructs the caller/model to scrape `OPENCLAW_FINAL_LINK:` from stdout and display it directly in chat during disconnect or recovery scenarios. Because the link represents an active order URL and the local state also stores order identifiers and pickup details, surfacing it without re-authentication or redaction can expose sensitive transactional data to the wrong user or any component with log/chat access.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
This script automates a real purchase flow by clicking the final submission controls ('确认提交' and popup '确认') using a user-supplied URL, and it proceeds by default unless --no-submit is explicitly set. That creates a genuine safety/security risk because running the skill can trigger an irreversible real-world transaction without an additional runtime confirmation, clear warning, or dry-run default.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The code clicks the final confirmation and waits for order completion without any explicit user-facing warning or secondary confirmation before the irreversible action. In an automation skill, this increases the risk of accidental purchases because callers may believe they are only validating UI flow while the script actually commits a transaction.

Natural-Language Policy Violations

Medium
Confidence
88% confidence
Finding
The script hardcodes locale="zh-CN", which imposes a specific language/locale behavior on all runs. The file does not indicate that this is optional, user-selected, or required for a region-specific compliance reason.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The script captures screenshots and later writes a JSON result file containing order details such as pickup code, order number, URL, and page state to disk. These artifacts can expose sensitive transactional information to other local users, logs, backup systems, or downstream tooling, especially because there is no minimization, retention control, or user consent around storing them.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
This script can place a real McDonald's order by clicking the final confirmation button automatically unless the caller explicitly supplies --no-submit. That creates a risky default for a purchasing workflow, because an agent or automation framework could trigger financial or real-world actions without an informed, user-facing confirmation step at execution time.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The script hard-codes locale="zh-CN" and a precise Shanghai geolocation into the browser context, which overrides user/environment settings and can misrepresent the operator's location to the target service. In an order-flow automation context, this can bypass region-specific behavior, produce misleading test results, or trigger actions under a falsified location context without explicit user awareness or consent.

External Transmission

Medium
Category
Data Exfiltration
Content
payload = {"username": identity, "phone": identity, "api_key": api_key}
    url = f"{base_url}/products"
    try:
        response = requests.post(url, json=payload, timeout=timeout)
        response.encoding = "utf-8"
        response.raise_for_status()
    except requests.RequestException as exc:
Confidence
90% confidence
Finding
This code transmits identity data and the API key to a configurable backend URL, which may be attacker-controlled if set via CLI or environment. In this skill's context, the transmitted data is sensitive account material, and the default development endpoint is plain HTTP, creating a real risk of credential exposure to local-network interception or misconfiguration.

External Transmission

Medium
Category
Data Exfiltration
Content
}
    url = f"{base_url.rstrip('/')}/order/status"
    try:
        response = requests.post(url, json=payload, timeout=timeout)
        response.encoding = "utf-8"
    except requests.RequestException as exc:
        raise RuntimeError(f"request failed: {exc}") from exc
Confidence
91% confidence
Finding
The order-status request sends identity, API key, and order ID to a user-configurable endpoint, exposing both authentication material and order metadata. Because this function may query and refresh live order status, directing it to an untrusted or insecure server could leak credentials and enable account/order reconnaissance.

External Transmission

Medium
Category
Data Exfiltration
Content
payload = {"username": identity, "phone": identity, "api_key": api_key}
    url = f"{base_url.rstrip('/')}/orders"
    try:
        response = requests.post(url, json=payload, timeout=timeout)
        response.encoding = "utf-8"
    except requests.RequestException as exc:
        raise RuntimeError(f"request failed: {exc}") from exc
Confidence
91% confidence
Finding
Listing server orders sends identity and API key to the configured backend, which exposes account-level order history if intercepted or sent to an attacker-controlled URL. In a commerce-related skill, that data is sensitive and the ability to enumerate orders materially increases privacy and fraud risk.

External Transmission

Medium
Category
Data Exfiltration
Content
payload["supplier_goods_id"] = supplier_goods_id
    url = f"{base_url}/order"
    try:
        response = requests.post(url, json=payload, timeout=timeout)
        response.encoding = "utf-8"
        response.raise_for_status()
    except requests.RequestException as exc:
Confidence
93% confidence
Finding
The order-placement request transmits identity, API key, product selection, pricing, and idempotency data to a configurable remote endpoint. In this skill context, that is especially sensitive because it can authorize real purchases; using a non-validated endpoint or insecure transport could leak credentials and transaction details or facilitate fraudulent order actions.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The skill persistently stores order URLs, order IDs, timestamps, product metadata, and related flow results in local JSON files without access controls, encryption, or clear user consent. Because these order links appear to enable continued order access or fulfillment, any other local user, malware, backup service, or log collector that can read the directory may obtain sensitive purchase data and potentially active ordering links.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
if args.no_final_submit or not args.allow_final_submit:
        cmd.append("--no-submit")

    proc = subprocess.run(cmd, capture_output=True, text=True, encoding="utf-8", errors="replace")
    result_file = extract_result_file(proc.stdout)
    if result_file is None:
        if proc.returncode != 0:
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
if args.no_final_submit or not args.allow_final_submit:
        cmd.append("--no-submit")

    proc = subprocess.run(cmd, capture_output=True, text=True, encoding="utf-8", errors="replace")
    result_file = extract_result_file(proc.stdout)
    if result_file is None:
        if proc.returncode != 0:
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
if args.no_final_submit or not args.allow_final_submit:
        cmd.append("--no-submit")

    proc = subprocess.run(cmd, capture_output=True, text=True, encoding="utf-8", errors="replace")
    result_file = extract_result_file(proc.stdout)
    if result_file is None:
        if proc.returncode != 0:
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
if args.no_final_submit or not args.allow_final_submit:
        cmd.append("--no-submit")

    proc = subprocess.run(cmd, capture_output=True, text=True, encoding="utf-8", errors="replace")
    result_file = extract_result_file(proc.stdout)
    if result_file is None:
        if proc.returncode != 0:
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
if args.no_final_submit or not args.allow_final_submit:
        cmd.append("--no-submit")

    proc = subprocess.run(cmd, capture_output=True, text=True, encoding="utf-8", errors="replace")
    result_file = extract_result_file(proc.stdout)
    if result_file is None:
        if proc.returncode != 0:
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Natural-Language Policy Violations

Low
Confidence
88% confidence
Finding
The code hard-codes locale="zh-CN" when creating the browser context. Under the policy, forcing a specific language or locale without opt-in is a natural-language policy concern unless the constraint is explicitly justified or user-selectable.

Natural-Language Policy Violations

Low
Confidence
97% confidence
Finding
The browser context is created with locale='zh-CN', which enforces a specific language/locale setting. The file does not offer a user choice or explain why the locale must be fixed, so this is a natural-language policy concern under the locale-choice rule.

Static analysis

No suspicious patterns detected.