Back to skill

Security audit

ClickMap

Security checks for vulnerabilities and agentic risk

Overview

ClickMap mostly does what it says, but its local bridge exposes saved browser automation targets with unsafe default access controls.

Review this before installing. Use it only if you are comfortable with a Chrome extension active on all sites and a local bridge storing page targets, selectors, and screen coordinates. If you install it, set CLICKMAP_TOKEN, keep the bridge on localhost, avoid mapping sensitive pages when possible, and treat synced/imported POIs as capable of changing where automation clicks.

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

Error
Location
scripts/bridge-server.js:8
Finding
Unauthenticated and Cross-Origin Accessible Local POI API<![CDATA[ ## Vulnerability Details **File Location**: `scripts/bridge-server.js`, lines 8-79 **Vulnerability Type**: Missing authentication by default, overly permissive CORS, and unrestricted request-body handling **Risk Level**: High ### Vulnerable Code ```javascript const TOKEN = process.env.CLICKMAP_TOKEN || ''; ``` ```javascript function send(res, code, payload) { res.writeHead(code, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' }); res.end(JSON.stringify(payload)); } function readBody(req) { return new Promise((resolve, reject) => { let raw = ''; req.on('data', chunk => (raw += chunk)); req.on('end', () => resolve(raw)); req.on('error', reject); }); } function authOk(req) { if (!TOKEN) return true; return req.headers['x-clickmap-token'] === TOKEN; } ``` ```javascript const server = http.createServer(async (req, res) => { if (req.method === 'OPTIONS') { res.writeHead(204, { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'GET,POST,OPTIONS', 'Access-Control-Allow-Headers': 'Content-Type, X-ClickMap-Token' }); return res.end(); } if (!authOk(req)) return send(res, 401, { ok: false, error: 'unauthorized' }); if (req.url === '/health' && req.method === 'GET') { return send(res, 200, { ok: true, service: 'clickmap-bridge', port: PORT, dataFile }); } if (req.url === '/api/pois' && req.method === 'GET') { return send(res, 200, { ok: true, ...loadData() }); } if (req.url === '/api/pois' && req.method === 'POST') { const raw = await readBody(req); let body; try { body = JSON.parse(raw || '{}'); } catch { return send(res, 400, { ok: false, error: 'invalid_json' }); } if (!Array.isArray(body.pois)) return send(res, 400, { ok: false, error: 'pois_array_required' }); const normalized = body.pois.map((p, idx) => ({ id: p.id || `poi-${Date.now()}-${idx}`, name: String(p.name || '').trim(), urlPa ...[truncated 4214 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. **Require authentication by default** - Generate a cryptographically random token during setup. - Refuse to start the bridge when no token is configured. - Do not treat an empty token as authorization for every request. - Compare supplied tokens using a constant-time comparison. 2. **Restrict browser origins** - Replace `Access-Control-Allow-Origin: *` with an explicit allowlist. - Permit only the expected Chrome extension origin. - Validate the incoming `Origin` header before processing requests. - Return no CORS headers to untrusted origins. - Apply the same checks to preflight and normal requests. 3. **Consider a safer transport** - Prefer Chrome native messaging for communication between the extension and local process. - Alternatively, use an authenticated operating-system IPC mechanism rather than a generally accessible HTTP service. 4. **Limit request sizes** - Track accumulated byte length while receiving a request. - Reject requests exceeding a small documented limit with HTTP `413 Payload Too Large`. - Destroy or stop reading the request after the limit is exceeded. - Limit the number of POIs and the length of every string field. 5. **Validate POI records** - Enforce a strict schema for names, URLs, selectors, metadata, and coordinates. - Require finite numeric coordinates within reasonable bounds. - Reject unexpected fields and malformed nested objects. - Use atomic writes and preserve a recoverable backup before replacing the complete POI file. 6. **Reduce exposed information** - Avoid returning the absolute `dataFile` path in `/health` and write responses. - Return only the fields required by the requesting component. - Consider separating read and write permissions or endpoints. 7. **Harden automation integrity** - Require explicit user confirmation before importing or replacing all targets. - Bind POIs to expected origins and verify t ...[truncated 112 chars]
Vulnerability Patterns
  • 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 Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (23)

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding
The skill is presented as a UI automation aid, but the analyzed behavior indicates it primarily exposes a localhost HTTP service and local file persistence rather than implementing the advertised click/type actions. Undisclosed network-listening and storage functionality broadens the attack surface: local processes could interact with the service or abuse stored POI data, while users and agents may underestimate the risk because the description sounds limited to browser automation.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The skill is presented as a UI automation aid, but the analyzed behavior indicates it primarily exposes a localhost HTTP service and local file persistence rather than implementing the advertised click/type actions. Undisclosed network-listening and storage functionality broadens the attack surface: local processes could interact with the service or abuse stored POI data, while users and agents may underestimate the risk because the description sounds limited to browser automation.

Ae1

High
Category
analysis-evasion
Content
- Local bridge: `scripts/bridge-server.js`
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
- Local bridge: `scripts/bridge-server.js`
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Lp3

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding
The skill advertises and instructs use of capabilities that involve environment access and a local network service, but it declares no explicit tool scope or permissions. That makes the operational boundary unclear to reviewers and agents, increasing the chance of unintended command execution, local service exposure, or use in contexts that would otherwise restrict such capabilities.

Description-Behavior Mismatch

Medium
Confidence
91% confidence
Finding
The background script exports saved click targets (POIs) to a configurable bridge over HTTP, which extends the extension's behavior beyond purely local browser UI automation. Because the bridge URL is configurable and defaults to cleartext localhost, the feature can expose potentially sensitive workflow metadata to another service without strong transport guarantees or clear in-file gating, increasing the risk of unintended data disclosure or abuse by a local malicious process.

Missing User Warnings

Medium
Confidence
85% confidence
Finding
The script sends stored POI data and an optional token to the bridge service without any visible warning, confirmation, or contextual notice in this file. In a tool used on internal dashboards, forms, and repetitive web tasks, those saved targets may reveal sensitive page structure or business workflow details, and cleartext HTTP to localhost may allow interception or misuse by local malware or another user-space process.

Context-Inappropriate Capability

Medium
Confidence
87% confidence
Finding
The code implements a bridge synchronization capability that is not necessary for merely saving and reusing on-screen click points inside Chrome. Extra communication paths increase attack surface: a compromised or spoofed bridge can receive automation metadata, and the extension becomes dependent on an external service whose trust model is not enforced here.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
This code stores rich POI metadata including page text, ARIA labels, element IDs, CSS/XPath selectors, URL path, and screen/page coordinates in extension storage, then triggers a sync message without presenting any explicit warning about the scope of captured data. On sensitive pages, these fields can unintentionally collect confidential or personal information from the DOM, and syncing increases the exposure surface beyond the local browser.

Context-Inappropriate Capability

Medium
Confidence
94% confidence
Finding
The manifest requests broad privileges (`tabs`, `scripting`, `activeTab`) plus host access to a local service, while the declared functionality does not clearly require blanket access across all sites. Overbroad extension permissions increase the blast radius if the extension is buggy, compromised, or later expanded to capture page data beyond the intended click-mapping use case.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The extension injects a content script on all URLs by default, even though its stated purpose is mapping and syncing named click targets. In a browser extension, `<all_urls>` gives code visibility and interaction capability across nearly every site the user visits, which creates unnecessary exposure to sensitive page content and makes abuse or accidental data collection more likely.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
This markdown/code-scope rule applies because this is an HTML code file with user-facing UI text. The interface exposes a potentially destructive operation, 'Clear All', but the surrounding UI text provides no warning, confirmation cue, or explanation of what data will be removed, which could lead to unintended loss of stored POIs or markings.

Context-Inappropriate Capability

Medium
Confidence
88% confidence
Finding
The extension allows a user-configurable arbitrary bridge URL and later POSTs stored POI data to it, creating an unrestricted data egress path. If the bridge is set to an attacker-controlled host or an insecure endpoint, saved automation targets and associated metadata can be exfiltrated or intercepted, which is more concerning in a browser automation skill that may target internal dashboards and sensitive workflows.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The bridge token is stored in chrome.storage.local in plaintext with no warning, scoping, or protection beyond extension storage. If the extension environment is compromised or debugging/export paths expose storage contents, the token could be recovered and reused to access the bridge service.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The manifest describes a Chrome UI automation skill centered on saving named on-screen targets and reusing them for reliable click/type actions. This code also transmits saved POIs to an external configurable bridge service over HTTP, which is a distinct synchronization/export capability not implied by the description's local browser-automation scope.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
POI data is transmitted over the network to a configurable endpoint when Sync is clicked, but the UI code does not provide explicit disclosure about the sensitivity of that data or the destination trust boundary. Because POIs may reflect internal application structure, workflow targets, or sensitive page associations, sending them to arbitrary hosts can leak operationally sensitive information.

Context-Inappropriate Capability

Medium
Confidence
87% confidence
Finding
The popup performs periodic network requests to a configurable bridge URL to check health, giving the extension an outbound communication channel beyond simple UI click-map automation. Because the endpoint is configurable and the code does not constrain it to localhost or a trusted origin, this can be abused to exfiltrate metadata, probe internal services, or silently expand trust boundaries if settings are altered.

Description-Behavior Mismatch

Medium
Confidence
92% confidence
Finding
The popup explicitly uploads the full saved POI set to a bridge service via POST, which expands the extension from local browser automation into external data transfer. POIs are tied to specific page origins and paths and may reveal internal URLs, workflow structure, and user-labeled targets, so sending them off-box creates confidentiality and scope-creep risk if the bridge is misconfigured, compromised, or pointed at a non-local endpoint.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
POI data is transmitted to the bridge without any visible warning, consent checkpoint, or per-sync disclosure in the popup flow. Even if POIs are 'just coordinates,' they include names and page associations that can expose sensitive application structure or user activity, so silent transfer undermines user expectations and increases privacy risk.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The server explicitly disables authentication when CLICKMAP_TOKEN is unset, yet still exposes a POST endpoint that overwrites the POI data file. Because it also enables permissive CORS and is intended for browser/UI automation, any local process or potentially a web page running in the user's browser could modify stored targets, leading to tampering of automation behavior and possible mis-click/type actions into sensitive applications.

Vague Triggers

Low
Confidence
79% confidence
Finding
This manifest file is in scope for vague-trigger review, and the description says the extension will 'Mark named points-of-interest on web pages' without clarifying when it activates, on which pages, or under what user action. That broad wording is made more concerning by the manifest also declaring a content script on all URLs, so the trigger scope is not narrowly specified in the user-facing manifest text.

Natural-Language Policy Violations

Low
Confidence
60% confidence
Finding
The description states that points-of-interest are synced to a local bridge, which is user-facing language about data handling, but it does not indicate whether this happens automatically or under user control. While not a definitive security flaw by itself, this natural-language behavior description lacks the clarity normally expected for potentially privacy-relevant synchronization behavior.

Natural-Language Policy Violations

Low
Confidence
42% confidence
Finding
This manifest-like JSON includes a named point of interest for a password input on a login page. While there is no direct code or instructional text, the natural-language label indicates handling of authentication fields without any accompanying justification or user-choice context, which is the only potentially relevant policy concern visible in this file.

Static analysis

Detected: suspicious.install_untrusted_source

Install source points to URL shortener or raw IP.

Warn
Code
suspicious.install_untrusted_source
Location
assets/chrome-extension/manifest.json:7