Back to skill

Security audit

web-llm-chat

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly does what it claims, but it controls an authenticated browser tab and lacks enough safeguards to prevent prompts or page contents from going to the wrong place.

Install only if you are comfortable letting the skill control an attached Qwen browser tab through your local Chrome Relay. Attach only genuine https://chat.qwen.ai tabs, avoid using read or html output on sensitive conversations, do not send secrets or personal data to Qwen unless you intend to, and pin dependencies before operational use.

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 (1)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/qwen_chat.js:280
Finding
Weak URL Validation Can Select an Attacker-Controlled Browser Tab## Vulnerability Details **File Location**: `scripts/qwen_chat.js:280-286` **Related Location**: `scripts/qwen_chat.js:400-405` **Vulnerability Type**: Improper origin validation **Risk Level**: Medium ### Vulnerable Code ```js async function getQwenTab(token) { const res = await httpGet(`http://127.0.0.1:${RELAY_PORT}/json`, { 'x-openclaw-relay-token': token }); if (res.status !== 200) throw new Error(`Relay /json failed: ${res.status}`); const tabs = JSON.parse(res.body); const qwen = tabs.find(t => t.url.includes('chat.qwen.ai')); if (!qwen) throw new Error('No Qwen Chat tab found. Open chat.qwen.ai in Chrome and attach extension.'); return qwen; } ``` The same unsafe matching pattern is also used by the status command: ```js const tabs = await httpGet(`http://127.0.0.1:${RELAY_PORT}/json`, { 'x-openclaw-relay-token': token }); const all = JSON.parse(tabs.body); const qwen = all.find(t => t.url.includes('chat.qwen.ai')); ``` ### Technical Analysis The script identifies a trusted Qwen tab using a substring search: ```js t.url.includes('chat.qwen.ai') ``` This does not validate the parsed URL's scheme or hostname. Consequently, it accepts unrelated URLs that merely contain the trusted domain as text, including: ```text https://attacker.example/?next=chat.qwen.ai https://chat.qwen.ai.attacker.example/ ``` After selection, the script attaches to the tab through the Chrome DevTools Protocol, executes JavaScript in its context, injects the user's prompt through input events, and extracts content from its DOM. Because `Array.find()` selects the first matching attached tab, an attacker-controlled tab appearing before the legitimate Qwen tab can be treated as the trusted destination. Relay authentication protects access to the local relay but does not establish that the selected browser page belongs to the expected HTTPS origin. ### Attack Path 1. An attacker causes a crafted page whose URL contains the string `chat.qwen.ai` to be o ...[truncated 1645 chars]
Remediation
## Remediation Suggestions Parse each candidate URL and require an exact trusted HTTPS origin rather than a substring match: ```js function isTrustedQwenUrl(value) { try { const url = new URL(value); return url.protocol === 'https:' && url.hostname === 'chat.qwen.ai' && url.port === ''; } catch { return false; } } ``` Apply the predicate consistently in both `getQwenTab()` and `status()`: ```js const qwenTabs = tabs.filter(tab => isTrustedQwenUrl(tab.url)); if (qwenTabs.length === 0) { throw new Error( 'No trusted Qwen Chat tab found. Open https://chat.qwen.ai and attach the extension.' ); } if (qwenTabs.length > 1) { throw new Error( 'Multiple trusted Qwen tabs are attached; select an explicit target before continuing.' ); } return qwenTabs[0]; ``` Additional hardening should include: 1. Revalidate the target's `location.origin` after CDP attachment and before injecting input: ```js const origin = await evalCmd('location.origin'); if (origin !== 'https://chat.qwen.ai') { throw new Error('Attached target has an unexpected origin'); } ``` 2. Require an explicit target ID when multiple legitimate Qwen tabs are attached. 3. Reject malformed URLs and non-HTTPS schemes. 4. Repeat origin validation before sensitive operations to reduce target-navigation race risks. 5. Add tests covering deceptive URLs, including subdomains, query strings, fragments, user-information components, and malformed values.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (26)

Ae1

High
Category
analysis-evasion
Content
node scripts/qwen_chat.js status
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/qwen_chat.js status
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/qwen_chat.js status
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/qwen_chat.js status
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/qwen_chat.js status
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/qwen_chat.js status
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/qwen_chat.js status
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/qwen_chat.js status
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/qwen_chat.js status
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/qwen_chat.js status
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/qwen_chat.js status
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/qwen_chat.js status
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/qwen_chat.js status
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Lp3

Medium
Category
MCP Least Privilege
Confidence
81% confidence
Finding
The skill exposes capabilities that can access environment-derived configuration and local relay/auth setup, but it declares no explicit tool scope or permissions. That weakens least-privilege controls and makes it harder for users or orchestrators to understand what the skill may access, increasing the chance of unintended data exposure or misuse.

Vague Triggers

Medium
Confidence
94% confidence
Finding
The trigger phrases are broad enough to match ordinary user requests about search, research, or browser AI chat, which can cause the skill to activate unexpectedly. Because this skill sends prompts to a third-party web LLM through a browser tab, accidental activation can leak sensitive user content or route tasks to an external service without clear intent.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The skill description emphasizes convenience and low cost but does not clearly warn that user prompts are transmitted to a third-party web LLM via an authenticated browser session. In this context, missing disclosure is more dangerous because the skill is specifically designed to relay potentially complex research prompts and follow-up context, which may contain confidential data or user-specific information.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The documentation explicitly exposes a `read` capability and an `html` output mode for the active Qwen chat page, but it does not warn that these features may capture prior conversation history, quoted prompts, account-related content, or other sensitive data visible in the tab. In an agent setting, this omission increases the chance that operators invoke the command in routine workflows and unintentionally exfiltrate more data than needed.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The document instructs users to configure a gateway token but does not warn that this token is sensitive authentication material that must not be exposed, logged, or shared. In a skill whose purpose is to bridge an agent to a browser-control relay, omission of token-handling guidance increases the chance of credential leakage and unauthorized access to the local relay or attached browser context.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The reference openly documents a workflow for attaching to browser tabs, executing JavaScript via Runtime.evaluate, and navigating pages, but provides no warning that these actions can access session-authenticated data, manipulate user actions, or compromise account integrity. Given this skill is specifically designed to control a live LLM browser tab through a relay, the lack of warnings and safety constraints makes misuse materially more dangerous than generic developer documentation.

Context-Inappropriate Capability

Medium
Confidence
89% confidence
Finding
The script reads local OpenClaw configuration files and derives a relay authentication token, giving the skill access to a privileged local capability unrelated to simple chat formatting or parsing. Even if intended for legitimate relay access, embedding credential discovery in the skill expands the blast radius: a skill can silently leverage host secrets to control the browser relay and access browser-tab data.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The readPage command attaches to the live Qwen tab and prints document.body.innerText, which can expose all visible content in that browser tab rather than only the response associated with the current user action. In this skill context, that means prior prompts, retrieved documents, search results, or other sensitive tab content can be exfiltrated to the caller without minimization or confirmation.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The page-reading path extracts and outputs the full visible text of the Qwen page without any warning, consent gate, or scoping to the current prompt/response. In a web-LLM skill, that is especially risky because the page may contain sensitive research data, previous conversations, or retrieved third-party content that the user did not intend to disclose through the agent.

Missing User Warnings

Medium
Confidence
81% confidence
Finding
The sendMessage flow types a user message into the Qwen Chat page and submits it, causing the content to be sent to an external service. While sending is part of the tool's purpose, the file lacks an explicit warning that prompts are transmitted to Qwen and later extracts the response and page content for local output.

Missing User Warnings

Low
Confidence
90% confidence
Finding
The documented support for raw HTML output and page reads lacks a clear warning that these operations can expose full conversation history, embedded page data, or other sensitive browser content. In a browser-relay skill, this materially increases risk because extraction/debug features can return more than the latest model answer, especially when users assume they are only getting a normal chat response.

Unpinned Dependencies

Low
Category
Supply Chain
Content
{
	"dependencies": {
		"ws": "^8.19.0"
	}
}
Confidence
96% confidence
Finding
The dependency uses a caret range (^8.19.0) instead of an exact pinned version, which makes builds non-reproducible and can silently pull in different ws releases over time. In a security-sensitive skill that relays data to a browser extension and web LLM, this increases supply-chain risk because a newly published vulnerable or compromised minor/patch release could be installed without review.

Static analysis

No suspicious patterns detected.