Back to skill

Security audit

Shopping in Sweden

Security checks for vulnerabilities and agentic risk

Overview

The skill is openly built to make online purchases, but it handles raw payment credentials and uses broad browser-control techniques in payment pages without enough scoping or safeguards.

Review carefully before installing. This skill should not be used with live payment cards unless you are comfortable giving the agent reusable card details and direct browser control over checkout frames. Prefer a version that uses tokenized or hosted payment, requires explicit approval before reading any private file, shows the final merchant/amount/address before payment, and removes hardcoded card data.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
Findings (4)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
SKILL.md:10
Finding
Unrestricted Access to Local Identity and Payment Credential Files<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:10-16` **Vulnerability Type**: Sensitive local file access that violates least-privilege principles **Risk Level**: High ### Vulnerable Code ```markdown ## User Information Read recipient details (address, phone, email) from `~/Private/用户个人信息.txt`. ## Payment Card Read Zupyak Mynt Card details from `~/Private/Zupyak Mynt card for AI.txt` or `~/.private/payment.env`. **Only use this designated card — never use the user's personal bank cards.** ``` ### Technical Analysis The Skill directs the agent to read identity information and raw payment credentials from fixed files in the user's home directory. The information potentially includes the recipient's address, email address, telephone number, card number, expiration date, and security code. Direct access to persistent secret files gives the agent reusable credentials rather than narrowly scoped, transaction-specific authorization. If malicious retailer content, prompt injection, or a compromised browser session influences the agent, these credentials could be disclosed or used outside the transaction intended by the user. The instruction limiting use to a designated card is a procedural safeguard, not a technical access-control boundary. It does not prevent the agent, another loaded Skill, or injected instructions from reading or misusing the data. ### Attack Path 1. The user invokes the shopping Skill. 2. The Skill instructs the agent to read the fixed PII and payment credential files. 3. A malicious or compromised shopping page presents instructions or content designed to influence the agent. 4. The agent reads reusable identity and payment secrets from the local filesystem. 5. The secrets are entered into an attacker-controlled, compromised, or unintended checkout. 6. The attacker obtains sensitive identity data, attempts unauthorized transactions, or both. ### Impact Assessment Successful exploitation could expose the user's delivery ...[truncated 477 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove instructions that expose raw card credentials directly to the agent. 2. Store payment credentials in a PCI-compliant vault and use tokenized payment methods. 3. Provide the agent with a transaction-scoped payment token restricted by: - Approved merchant - Maximum amount - Currency - Expiration time - Single-use enforcement 4. Obtain recipient information through a constrained interface that returns only the fields required for the current order. 5. Require explicit user approval after displaying the merchant, final amount, delivery address, and selected payment method. 6. Prevent page content and other Skills from accessing secret-retrieval tools. 7. Record auditable access events without logging PII, card data, or authentication secrets. 8. Rotate or revoke any credentials that may already have been exposed to untrusted agent contexts. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
references/cdp-click.md:1
Finding
Cross-Origin Payment Controls Bypassed Through Unrestricted Chrome DevTools Protocol Access<![CDATA[ ## Vulnerability Details **File Location**: `references/cdp-click.md:1-15, 21-65` **Vulnerability Type**: Browser security-boundary bypass and excessive browser privileges **Risk Level**: High ### Vulnerable Code ```markdown # CDP Coordinate Click — Bypassing Cross-Origin Iframes ## Background The browser's same-origin policy prevents JavaScript from accessing the DOM of cross-origin iframes, which means the browser tool's ref/selector clicks do not work on Klarna/Stripe/Adyen payment iframes. **Solution:** Use Chrome DevTools Protocol (CDP) to connect directly to the iframe's independent target, execute JS inside it, and dispatch mouse events. Physical mouse events are not subject to same-origin policy. ## CDP Connection OpenClaw exposes the CDP interface at `ws://127.0.0.1:18800`. ```bash # List all targets (pages and iframes) curl -s http://127.0.0.1:18800/json ``` ``` ```python import socket, struct, json, time, base64 as b64 def ws_connect(target_id): s = socket.socket() s.connect(('127.0.0.1', 18800)) key = b64.b64encode(b'openclaw-cdp-key').decode() h = (f"GET /devtools/page/{target_id} HTTP/1.1\r\n" f"Host: 127.0.0.1:18800\r\n" f"Upgrade: websocket\r\nConnection: Upgrade\r\n" f"Sec-WebSocket-Key: {key}\r\nSec-WebSocket-Version: 13\r\n\r\n") s.send(h.encode()) s.recv(2048) return s def ws_send(s, mid, method, params={}): d = json.dumps({'id': mid, 'method': method, 'params': params}).encode() n = len(d) mask = b'\x01\x02\x03\x04' masked = bytes(b ^ mask[i%4] for i,b in enumerate(d)) hdr = bytes([0x81, 0x80|n]) + mask if n<=125 else bytes([0x81,0xFE])+struct.pack('>H',n)+mask s.send(hdr+masked) def ws_recv(s, timeout=4): results = [] s.settimeout(timeout) while True: try: h = s.recv(2) n = h[1]&0x7F if n==126: n=struct.unpack('>H',s.recv(2))[0] elif n==127: n=struct.unpack('>Q',s.recv(8))[0 ...[truncated 2912 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove raw CDP target enumeration and arbitrary `Runtime.evaluate` access from the Skill. 2. Use a constrained browser or payment API that exposes only the operations needed for the current transaction. 3. Prefer provider-supported hosted checkout flows and tokenized payment interfaces. 4. If CDP access is operationally unavoidable: - Run the checkout in a dedicated, isolated browser profile. - Expose only the active checkout target. - Authenticate and authorize every CDP connection. - Disable arbitrary JavaScript evaluation. - Allow only narrowly defined input events. - Apply exact origin and parent-frame validation. - Terminate the isolated browser after the transaction. 5. Require an unskippable user confirmation immediately before any event that places an order or authorizes payment. 6. Bind confirmation to the verified merchant, final total, currency, recipient, and order contents. 7. Reject operations when more than one candidate payment target exists. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
references/cdp-click.md:154
Finding
Plaintext Payment-Card Number, Expiration Date, and CVC Embedded in Documentation<![CDATA[ ## Vulnerability Details **File Location**: `references/cdp-click.md:154-158` **Vulnerability Type**: Hardcoded payment credentials and plaintext sensitive data **Risk Level**: Critical ### Vulnerable Code ```python # Fill in card details (read from ~/Private/) type_into_input(s, "number", "4273 1800 0443 8968", 10) type_into_input(s, "expiry", "03/31", 20) type_into_input(s, "cvc", "991", 30) s.close() ``` ### Technical Analysis The repository contains a complete payment-card number, expiration date, and CVC in plaintext. The values are supplied directly to card-entry functions and are presented as part of an operational Stripe payment workflow. The source does not label these values as provider-issued test credentials. Consequently, they must be treated as potentially usable payment credentials. Anyone able to read the Skill package, a copy of the repository, generated documentation, backups, logs, or repository history can recover them without additional authentication. Embedding a CVC is particularly sensitive because it creates a readily reusable card-not-present credential set and is inconsistent with secure payment credential handling. ### Attack Path 1. An attacker obtains read access to the Skill package, repository, artifact archive, backup, or repository history. 2. The attacker opens `references/cdp-click.md`. 3. The attacker extracts the card number, expiration date, and CVC. 4. The attacker attempts card-not-present transactions using the recovered values. 5. If the card is active and no additional controls block the payment, unauthorized charges may be placed. ### Impact Assessment If the values belong to an active card, exploitation could result in unauthorized purchases, financial loss, card suspension, incident-response costs, and payment-security compliance consequences. The exposed scope is the specific card account represented by the embedded credentials. The finding does not establish access to other cards, bank accoun ...[truncated 177 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Immediately determine whether the embedded card is real. 2. If it is real, revoke or freeze it and issue replacement credentials. 3. Remove the PAN, expiration date, and CVC from the current files and all accessible repository history. 4. Review artifact archives, build outputs, logs, backups, forks, and caches for additional copies. 5. Do not replace the values with another production secret. 6. Use clearly documented payment-provider test tokens or official sandbox card numbers in examples. 7. Store production payment credentials in a PCI-compliant vault and expose only single-use payment tokens. 8. Add automated secret scanning to source-control and release pipelines. 9. Configure secret-scanning rules to detect PAN patterns and nearby expiration/CVC values. 10. Prevent payment input values from being written to console output, screenshots, telemetry, or exception logs. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
references/cdp-click.md:144
Finding
Payment Data Injected into CDP Targets Selected by Weak URL Substring Matching<![CDATA[ ## Vulnerability Details **File Location**: `references/cdp-click.md:144-158` **Vulnerability Type**: Insufficient payment-frame origin and transaction validation **Risk Level**: High ### Vulnerable Code ```python # Find the Stripe elements-inner target tabs = json.loads(urllib.request.urlopen('http://127.0.0.1:18800/json').read()) stripe = next(t for t in tabs if 'stripe.com/v3/elements-inner-accessory' in t.get('url','')) s = ws_connect(stripe['id']) # Verify input fields are present ws_send(s, 1, 'Runtime.evaluate', {'expression': 'JSON.stringify(Array.from(document.querySelectorAll("input[name]")).map(i=>({name:i.name,placeholder:i.placeholder})))'}) # Should return: number, expiry, cvc # Fill in card details (read from ~/Private/) type_into_input(s, "number", "4273 1800 0443 8968", 10) type_into_input(s, "expiry", "03/31", 20) type_into_input(s, "cvc", "991", 30) ``` ### Technical Analysis The payment iframe is selected when its URL contains the substring `stripe.com/v3/elements-inner-accessory`. The code does not parse and verify the complete origin, confirm HTTPS, validate the target's parent frame, bind the iframe to the approved top-level retailer, or confirm that it belongs to the transaction authorized by the user. The use of `next(...)` selects the first matching target. If multiple Stripe frames exist because of another open tab, a stale checkout, an attacker-induced frame, or a compromised merchant page, the code may inject card credentials into the wrong target. Verifying that fields named `number`, `expiry`, and `cvc` exist does not prove that the frame belongs to the expected merchant or transaction. Those field names can be reproduced by an unintended payment form. ### Attack Path 1. An attacker causes an additional matching payment target to be present in the browser, such as through a malicious page, compromised retailer content, or stale checkout. 2. The Skill enumerates all CDP targets. 3. The substring test identifies ...[truncated 810 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not select payment targets using raw substring checks. 2. Parse target URLs and require an exact allowlisted HTTPS origin and expected path. 3. Verify the complete frame hierarchy and bind the payment frame to the approved top-level retailer. 4. Bind the selected frame to a unique transaction identifier generated for the current checkout. 5. Verify the merchant identity, order contents, final amount, and currency immediately before entering payment information. 6. Require exactly one eligible payment target; abort if no target or multiple targets match. 7. Isolate each checkout in a new browser profile with no unrelated pages or stale payment frames. 8. Prefer provider-generated client secrets, hosted checkout sessions, and single-use payment tokens over raw card entry. 9. Require renewed user authorization if the merchant, amount, frame identity, or checkout session changes. 10. Avoid using DOM field names alone as proof of payment-provider or merchant authenticity. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (12)

Context-Inappropriate Capability

Critical
Confidence
100% confidence
Finding
The code directly inputs card number, expiry, and CVC into Stripe fields, including hard-coded example values and instructions to read card data from private storage. In an unknown-purpose skill, this is a highly sensitive financial capability that could be used to process unauthorized transactions or facilitate payment credential misuse.

Missing User Warnings

High
Confidence
98% confidence
Finding
The skill instructs the agent to read sensitive local files containing recipient details and payment card data, but it does not present a clear warning or obtain explicit user consent for that access. Because these files contain high-value PII and financial data, silent access creates a substantial privacy and security risk even before any purchase is completed.

Missing User Warnings

High
Confidence
99% confidence
Finding
The skill directs the agent to use CDP WebSocket access and synthetic mouse events to interact with cross-origin payment iframes, effectively bypassing normal browser-tool restrictions. This is especially dangerous in a payment context because it enables automation of sensitive checkout actions without transparent, user-visible safeguards and expands the attack surface around payment credential handling.

Context-Inappropriate Capability

High
Confidence
99% confidence
Finding
The document explicitly describes bypassing same-origin protections by attaching to cross-origin iframe targets over CDP and dispatching input into payment frames. That materially expands an agent’s ability to interact with third-party payment contexts in ways normal browser automation intentionally forbids, enabling unauthorized purchase flows, payment confirmation clicks, and abuse of trusted checkout surfaces.

Missing User Warnings

High
Confidence
97% confidence
Finding
The skill automates entry of highly sensitive financial data without warnings, consent requirements, masking expectations, or storage/handling constraints. Even if intended for testing, presenting this as routine automation normalizes unsafe handling of cardholder data and increases the chance of misuse or accidental exposure.

Vague Triggers

Medium
Confidence
96% confidence
Finding
The trigger phrases are broad enough to activate on common shopping-related requests, which can cause the skill to engage high-risk behaviors such as reading local PII files and initiating purchases with insufficiently explicit intent. In a payment-capable skill, overbroad activation materially increases the chance of unintended data access or transaction flow initiation.

Intent-Code Divergence

Medium
Confidence
98% confidence
Finding
The skill claims user information is never shared with third parties, but its documented payment flow explicitly routes payment through third-party processors such as Klarna, Stripe, or Adyen. This creates a misleading privacy guarantee that could cause users to consent without understanding where their personal and payment-related data is actually sent.

Natural-Language Policy Violations

Medium
Confidence
91% confidence
Finding
The instructions target a button labeled "Betala köp" and assume a Swedish-language Klarna flow, but the document does not state that the skill is Swedish-locale-specific or provide an opt-in or alternative for other languages. This creates a natural-language locale constraint that is undocumented and effectively forced.

Internal Network Request

Medium
Category
Server-Side Request Forgery
Content
import urllib.request

# 1. Click "Betala köp" inside the Klarna iframe
tabs = json.loads(urllib.request.urlopen('http://127.0.0.1:18800/json').read())
kustom = next(t for t in tabs if 'kustom' in t.get('url','') and 'template' in t.get('url',''))

s = ws_connect(kustom['id'])
Confidence
70% confidence
Finding
Code issues a request to a loopback, link-local, or private-range host. This can reach internal services not meant to be exposed and is a common SSRF pivot.

Internal Network Request

Medium
Category
Server-Side Request Forgery
Content
import urllib.request

# 1. Click "Betala köp" inside the Klarna iframe
tabs = json.loads(urllib.request.urlopen('http://127.0.0.1:18800/json').read())
kustom = next(t for t in tabs if 'kustom' in t.get('url','') and 'template' in t.get('url',''))

s = ws_connect(kustom['id'])
Confidence
70% confidence
Finding
Code issues a request to a loopback, link-local, or private-range host. This can reach internal services not meant to be exposed and is a common SSRF pivot.

Internal Network Request

Medium
Category
Server-Side Request Forgery
Content
import urllib.request

# 1. Click "Betala köp" inside the Klarna iframe
tabs = json.loads(urllib.request.urlopen('http://127.0.0.1:18800/json').read())
kustom = next(t for t in tabs if 'kustom' in t.get('url','') and 'template' in t.get('url',''))

s = ws_connect(kustom['id'])
Confidence
70% confidence
Finding
Code issues a request to a loopback, link-local, or private-range host. This can reach internal services not meant to be exposed and is a common SSRF pivot.

Natural-Language Policy Violations

Low
Confidence
72% confidence
Finding
The instruction references a fixed path `~/Private/用户个人信息.txt`, which assumes a particular filename and language convention. The file does not indicate that users can choose or configure their preferred language or locale for such resources, creating a mild language-policy concern.

Static analysis

No suspicious patterns detected.