Back to skill

Security audit

webchat-extension

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent browser AI helper, but it over-collects clipboard data and exposes an authenticated local AI backend without enough access control.

Review before installing. This skill can read and persist clipboard text, send selected or copied content to CodeBuddy AI, use your local CodeBuddy login or API key, register a Windows protocol handler, and run a local backend. It should be tightened with explicit clipboard confirmation, backend authentication, loopback-only binding, restricted CORS, source checks for panel messages, and updated dependencies before use with sensitive 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 (5)

T09 · Insecure Skill Coding Practices

Error
Location
assets/backend/server.js:176
Finding

Unauthenticated AI Backend Exposed to Websites and Local Network Clients

Content
View full analysis
{ // Authentication probe that uses the configured API key or local CLI login. // No client authentication is required to invoke it. ... }); app.post("/api/chat", async (req, res) => { const { context = "", question = "", history = [], pageTitle = "", pageUrl = "", } = req.body || {}; ... const stream = query({ prompt, options: { cwd: process.cwd(), model: MODEL, maxTurns: 5, systemPrompt, permissionMode: "default", canUseTool, pathToCodebuddyCode: CODEBUDDY_CLI, env: sdkEnv, }, }); ... }); app.post("/api/stop", (req, res) => { res.json({ status: "stopping" }); setTimeout(() => { killOwnCli(); process.exit(0); }, 300); }); ``` ```js app.listen(PORT, () => { console.log(`\n◉ Web highlight chat backend started: http://localhost:${PORT}`); ... }); ``` ### Technical Analysis The backend does not authenticate requests to `/api/chat`, `/api/auth`, `/api/heartbeat`, or `/api/stop`. The default CORS configuration explicitly permits every web origin. Consequently, JavaScript on an ...[truncated 2334 chars]
Remediation
View remediation
{ console.log(`Backend listening on http://127.0.0.1:${PORT}`); }); ``` 2. Generate a cryptographically random authorization token during deployment or startup: ```js import crypto from "node:crypto"; const CLIENT_TOKEN = process.env.WEBCHAT_CLIENT_TOKEN || crypto.randomBytes(32).toString("hex"); ``` 3. Require the token on every sensitive endpoint, including chat, authentication probes, heartbeat, and stop: ```js function requireClientToken(req, res, next) { const supplied = req.get("X-Webchat-Token"); if (!supplied || supplied !== CLIENT_TOKEN) { return res.status(401).json({ error: "Unauthorized" }); } next(); } app.use("/api/chat", requireClientToken); app.use("/api/auth", requireClientToken); app.use("/api/heartbeat", requireClientToken); app.use("/api/stop", requireClientToken); ``` 4. Restrict CORS to the installed extension's exact `chrome-extension://` origin. Do not default to `*`. 5. Reject missing, `null`, or unexpected `Origin` values as appropriate for the intended client. 6. Add rate limiting, request concurrency limits, and explicit request-size limits. 7. Consider using native messaging or an authenticated local IPC mechanism instead of an unauthenticated HTTP service. 8. Avoid returning unnecessary authentication and internal port metadata from the health endpoint. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
assets/extension/panel.js:227
Finding

Automatic Capture, Persistent Storage, and Transmission of Clipboard Contents

Content
View full analysis
({ role: m.role, content: m.content }))); } ``` ```js async function readClipboardAsync() { try { if (navigator.clipboard && navigator.clipboard.readText) { const t = (await navigator.clipboard.readText()).trim(); if (t) return t; } } catch (_) {} return ""; } async function readClipboard() { const a = await readClipboardAsync(); if (a) return a; return readClipboardSync(); } ``` ```js async function send() { const q = inputEl.value.trim(); if (!q) return; addMessage("user", q); inputEl.value = ""; saveMessages(); // Automatically collect clipboard contents during every send. const clip = await readClipboard(); let autoAdded = 0; if (clip) { if (addContext(clip)) autoAdded++; } else if (q) { if (addContext(q)) autoAdded++; } const assistant = addMessage("assistant", ""); const history = messages .filter((m) => m.role !== "assistant" || m !== assistant) .map((m) => ({ role: m.role, content: m.content })); const body = { context: contexts.join("\n---\n"), question: q, history: history, pageTitle: pageInfo.title, pageUrl: pageInfo.url, }; const resp = await fetch(BACKEND + "/api/chat", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body), }); ... } ``` ### Technical Analysis The extension requests the `clipboardRead` permission and attempts to read the system clipboar ...[truncated 2132 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
assets/extension/content.js:61
Finding

Untrusted Webpages Can Spoof Privileged Panel Messages and Trigger the Protocol Handler

Content
View full analysis
Remediation
View remediation
{ if (!panelIframe || ev.source !== panelIframe.contentWindow) return; const expectedOrigin = new URL(chrome.runtime.getURL("panel.html")).origin; if (ev.origin !== expectedOrigin) return; const d = ev.data; if (!d || d.nonce !== panelNonce) return; // Process an explicit allowlist of message types. }); ``` 2. Generate a cryptographically random nonce whenever a panel is opened and include it in both directions of panel communication. 3. Reject all panel commands when no active panel exists. 4. Validate numeric drag offsets and enforce strict bounds. 5. Prefer `chrome.runtime.sendMessage()` or a dedicated extension port for privileged operations. 6. Require a direct extension UI action before invoking a native protocol handler. 7. Add throttling so repeated launch messages cannot cause repeated protocol invocations. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
assets/backend/server.js:102
Finding

Command Injection Through Configurable CLI Path During Process Cleanup

Content
View full analysis
Remediation
View remediation
1 && pid !== process.pid) { process.kill(pid, "SIGKILL"); } } ``` 3. Avoid generating PowerShell source containing configuration values. Use a helper script with safely encoded parameters or implement process-tree handling through a library that does not invoke a shell. 4. Canonicalize `CODEBUDDY_CLI_PATH` with `fs.realpathSync()`. 5. Require it to point to an existing regular file. 6. Restrict it to approved CodeBuddy installation directories. 7. Reject control characters, quotes, line breaks, and unexpected filename forms. 8. Track child PIDs when they are created and terminate only those recorded PIDs, avoiding global process searches where possible. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
assets/backend/server.js:288
Finding

Untrusted Webpage Content Is Inserted Directly Into the Model System Prompt

Content
View full analysis
({ behavior: "deny", message: "This extension only supports text Q&A and does not permit tools", }); const stream = query({ prompt, options: { cwd: process.cwd(), model: MODEL, maxTurns: 5, systemPrompt, permissionMode: "default", canUseTool, pathToCodebuddyCode: CODEBUDDY_CLI, env: sdkEnv, }, }); ``` ### Technical Analysis The selected webpage text, page title, and URL are attacker-controllable when the user visits an untrusted website. These values are concatenated directly into the model's system prompt, which normally has greater authority than user messages. Delimiters such as triple quotation marks do not create a security boundary for a language model. A malicious webpage can include text instructing the model to disregard prior rules, misrepresent content, request unrelated sensitive information, or produce attacker-selected output. The implementation denies model tool use, which substantially limits direct system impact. However, prompt injection can still undermine response integrity, mislead the user, manipulate generated content, and influence how persisted chat history is interpreted. ### Attack Path 1. ...[truncated 1306 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
Findings (67)

Missing User Warnings

High
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill describes sending selected webpage text, copied text, and page context through a local backend to an AI service, but it does not present a prominent user-facing warning about that data flow. This is dangerous because users may paste or select sensitive material without realizing it will be retained locally in extension state and transmitted for remote model processing.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 45)May include surrounding context.

md
> **统一原则**:本 skill 是**唯一 source of truth**。运行环境一律由 `deploy.mjs` 生成(assets → 目标目录),不要在别处手维护一份带 `extension/ backend/` 的"双形态"目录,以免与 skill 不同步产生歧义。deploy 产物(目标目录)本身

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 78)May include surrounding context.

md
> **统一原则**:本 skill 是**唯一 source of truth**。运行环境一律由 `deploy.mjs` 生成(assets → 目标目录),不要在别处手维护一份带 `extension/ backend/` 的"双形态"目录,以免与 skill 不同步产生歧义。deploy 产物(目标目录)本身

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 79)May include surrounding context.

md
> **统一原则**:本 skill 是**唯一 source of truth**。运行环境一律由 `deploy.mjs` 生成(assets → 目标目录),不要在别处手维护一份带 `extension/ backend/` 的"双形态"目录,以免与 skill 不同步产生歧义。deploy 产物(目标目录)本身

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 55)May include surrounding context.

md
deploy 产物(目标目录)即为双形态目录,内含 `pack.mjs`。在其中运行:

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 60)May include surrounding context.

md
deploy 产物(目标目录)即为双形态目录,内含 `pack.mjs`。在其中运行:

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 79)May include surrounding context.

md
deploy 产物(目标目录)即为双形态目录,内含 `pack.mjs`。在其中运行:

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 63)May include surrounding context.

md
后端 `server.js` 通过 CodeBuddy Agent SDK 调真实模型,认证方式参考 dingtalk-auto-reply 的「Key / CLI 已登录」范式:

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 73)May include surrounding context.

md
后端 `server.js` 通过 CodeBuddy Agent SDK 调真实模型,认证方式参考 dingtalk-auto-reply 的「Key / CLI 已登录」范式:

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 75)May include surrounding context.

md
后端 `server.js` 通过 CodeBuddy Agent SDK 调真实模型,认证方式参考 dingtalk-auto-reply 的「Key / CLI 已登录」范式:

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 81)May include surrounding context.

md
ware\Classes\webchat` 注册表项丢失/损坏导致,Windows 找不到处理程序就去 Store 找 UWP 应用了。修复:运行 `node scripts/register-protocol.cjs`(自动探测 `launcher.vbs` 位置并重新注册协议,支持 `--check` 仅检查、`-

Missing User Warnings

High
Category
Not specified by scanner
Confidence
96% confidence
Finding

The usage instructions state that sending will automatically collect clipboard content and question text into context, but they do not warn users that this may include sensitive data and will be processed by the backend/AI system. Automatic ingestion of clipboard data is particularly risky because clipboard contents often contain passwords, tokens, personal data, or proprietary text copied for unrelated purposes.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · assets/backend/launcher.mjs (reported line 19)May include surrounding context.

js
// 应用端口(用于探测后端是否已在线),默认 3000
let PORT = 3000;
// CLI prewarm 端口(由 SERVER__PORT 控制,避开 WorkBuddy 桌面占用的端口冲突)。
// null 表示「用户没在 .env 显式设置」→ 不注入,让 server.js 自己分配空闲端口;
// 非 null 表示用户显式设置了 → 显式注入,覆盖本机可能存在的系统级 SERVER__PORT,
// 否则 dotenv 不覆盖已存在环境变量,CLI prewarm 会撞上被占用的端口导致卡死。
let SERVER_PORT = null;

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · assets/backend/launcher.mjs (reported line 57)May include surrounding context.

js
// 应用端口(用于探测后端是否已在线),默认 3000
let PORT = 3000;
// CLI prewarm 端口(由 SERVER__PORT 控制,避开 WorkBuddy 桌面占用的端口冲突)。
// null 表示「用户没在 .env 显式设置」→ 不注入,让 server.js 自己分配空闲端口;
// 非 null 表示用户显式设置了 → 显式注入,覆盖本机可能存在的系统级 SERVER__PORT,
// 否则 dotenv 不覆盖已存在环境变量,CLI prewarm 会撞上被占用的端口导致卡死。
let SERVER_PORT = null;

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · assets/backend/server.js (reported line 71)May include surrounding context.

js
// 应用端口(用于探测后端是否已在线),默认 3000
let PORT = 3000;
// CLI prewarm 端口(由 SERVER__PORT 控制,避开 WorkBuddy 桌面占用的端口冲突)。
// null 表示「用户没在 .env 显式设置」→ 不注入,让 server.js 自己分配空闲端口;
// 非 null 表示用户显式设置了 → 显式注入,覆盖本机可能存在的系统级 SERVER__PORT,
// 否则 dotenv 不覆盖已存在环境变量,CLI prewarm 会撞上被占用的端口导致卡死。
let SERVER_PORT = null;

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · assets/backend/server.js (reported line 167)May include surrounding context.

js
// 应用端口(用于探测后端是否已在线),默认 3000
let PORT = 3000;
// CLI prewarm 端口(由 SERVER__PORT 控制,避开 WorkBuddy 桌面占用的端口冲突)。
// null 表示「用户没在 .env 显式设置」→ 不注入,让 server.js 自己分配空闲端口;
// 非 null 表示用户显式设置了 → 显式注入,覆盖本机可能存在的系统级 SERVER__PORT,
// 否则 dotenv 不覆盖已存在环境变量,CLI prewarm 会撞上被占用的端口导致卡死。
let SERVER_PORT = null;

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · assets/backend/server.js (reported line 275)May include surrounding context.

js
// 应用端口(用于探测后端是否已在线),默认 3000
let PORT = 3000;
// CLI prewarm 端口(由 SERVER__PORT 控制,避开 WorkBuddy 桌面占用的端口冲突)。
// null 表示「用户没在 .env 显式设置」→ 不注入,让 server.js 自己分配空闲端口;
// 非 null 表示用户显式设置了 → 显式注入,覆盖本机可能存在的系统级 SERVER__PORT,
// 否则 dotenv 不覆盖已存在环境变量,CLI prewarm 会撞上被占用的端口导致卡死。
let SERVER_PORT = null;

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · assets/backend/server.js (reported line 429)May include surrounding context.

js
// 应用端口(用于探测后端是否已在线),默认 3000
let PORT = 3000;
// CLI prewarm 端口(由 SERVER__PORT 控制,避开 WorkBuddy 桌面占用的端口冲突)。
// null 表示「用户没在 .env 显式设置」→ 不注入,让 server.js 自己分配空闲端口;
// 非 null 表示用户显式设置了 → 显式注入,覆盖本机可能存在的系统级 SERVER__PORT,
// 否则 dotenv 不覆盖已存在环境变量,CLI prewarm 会撞上被占用的端口导致卡死。
let SERVER_PORT = null;

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · assets/root/README.md (reported line 30)May include surrounding context.

md
// 应用端口(用于探测后端是否已在线),默认 3000
let PORT = 3000;
// CLI prewarm 端口(由 SERVER__PORT 控制,避开 WorkBuddy 桌面占用的端口冲突)。
// null 表示「用户没在 .env 显式设置」→ 不注入,让 server.js 自己分配空闲端口;
// 非 null 表示用户显式设置了 → 显式注入,覆盖本机可能存在的系统级 SERVER__PORT,
// 否则 dotenv 不覆盖已存在环境变量,CLI prewarm 会撞上被占用的端口导致卡死。
let SERVER_PORT = null;

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · assets/root/README.md (reported line 52)May include surrounding context.

md
// 应用端口(用于探测后端是否已在线),默认 3000
let PORT = 3000;
// CLI prewarm 端口(由 SERVER__PORT 控制,避开 WorkBuddy 桌面占用的端口冲突)。
// null 表示「用户没在 .env 显式设置」→ 不注入,让 server.js 自己分配空闲端口;
// 非 null 表示用户显式设置了 → 显式注入,覆盖本机可能存在的系统级 SERVER__PORT,
// 否则 dotenv 不覆盖已存在环境变量,CLI prewarm 会撞上被占用的端口导致卡死。
let SERVER_PORT = null;

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/deploy.mjs (reported line 110)May include surrounding context.

js
// 应用端口(用于探测后端是否已在线),默认 3000
let PORT = 3000;
// CLI prewarm 端口(由 SERVER__PORT 控制,避开 WorkBuddy 桌面占用的端口冲突)。
// null 表示「用户没在 .env 显式设置」→ 不注入,让 server.js 自己分配空闲端口;
// 非 null 表示用户显式设置了 → 显式注入,覆盖本机可能存在的系统级 SERVER__PORT,
// 否则 dotenv 不覆盖已存在环境变量,CLI prewarm 会撞上被占用的端口导致卡死。
let SERVER_PORT = null;

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · assets/backend/launcher.mjs (reported line 24)May include surrounding context.

js
// 否则 dotenv 不覆盖已存在环境变量,CLI prewarm 会撞上被占用的端口导致卡死。
let SERVER_PORT = null;
try {
  const txt = fs.readFileSync(path.join(__dirname, ".env"), "utf8");
  const mP = txt.match(/^\s*PORT\s*=\s*(\d+)/m);
  if (mP) PORT = parseInt(mP[1], 10);
  const mS = txt.match(/^\s*SERVER__PORT\s*=\s*(\d+)/m);

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/deploy.mjs (reported line 133)May include surrounding context.

js
// 否则 dotenv 不覆盖已存在环境变量,CLI prewarm 会撞上被占用的端口导致卡死。
let SERVER_PORT = null;
try {
  const txt = fs.readFileSync(path.join(__dirname, ".env"), "utf8");
  const mP = txt.match(/^\s*PORT\s*=\s*(\d+)/m);
  if (mP) PORT = parseInt(mP[1], 10);
  const mS = txt.match(/^\s*SERVER__PORT\s*=\s*(\d+)/m);

Known Vulnerable Dependency: fast-uri==3.1.3 — 6 advisory(ies): CVE-2026-75931 (fast-uri vulnerable to host confusion via skipped IDN canonicalization on scheme); CVE-2026-18446 (fast-uri vulnerable to host confusion via backslash authority introducer); CVE-2026-75975 (fast-uri vulnerable to server-side request forgery via malformed IPv6 normalizat) +3 more

High
Category
Supply Chain
Confidence
80% confidence
Finding

fast-uri 3.1.3 is present with multiple high-severity URI parsing issues including host confusion and potential SSRF-relevant normalization bugs. This matters more in a webchat backend because the service brokers requests to AI/agent infrastructure, where malformed URLs in config, tools, or connectors could lead to incorrect trust decisions or outbound requests to unintended hosts.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: ip-address==10.2.0 — 3 advisory(ies): CVE-2026-54272 (ip-address: misclassification of IPv4-mapped/NAT64 IPv6 addresses can bypass SSR); CVE-2026-69198 (ip-address: a CIDR suffix on the parsed address suppresses special-use classific); CVE-2026-69192 (ip-address: Address4 decodes leading-zero octets as decimal while resolvers deco)

High
Category
Supply Chain
Confidence
80% confidence
Finding

ip-address 10.2.0 has advisories for special-address misclassification that can enable SSRF protections to be bypassed. In an agent-backed web extension context, this is relevant because server components often mediate outbound connections or tool access, and incorrect IP classification can undermine localhost/private-network blocking if such controls exist upstream in the SDK stack.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.dangerous_exec, suspicious.install_untrusted_source

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
assets/backend/launcher.mjs:61

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
assets/backend/server.js:135

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/deploy.mjs:159

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/register-protocol.cjs:56

Install source points to URL shortener or raw IP.

Warn
Code
suspicious.install_untrusted_source
Location
assets/extension/manifest.json:23