Back to skill

Security audit

OpenClaw Token Monitor

Security checks for vulnerabilities and agentic risk

Overview

The skill is a real token-usage monitor, but it exposes detailed session telemetry over an unauthenticated network service and has concrete web/API security flaws.

Install only if you are comfortable running a local Node dashboard that records token-usage history. Before using it on a shared or reachable network, bind it to localhost, add authentication, remove wildcard CORS, validate date inputs, avoid innerHTML for session data, and decide how long session-level history should be kept.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (4)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/token-monitor.js:336
Finding

Unauthenticated Network Exposure of Sensitive Session Telemetry

Content
View full analysis
{ clients = clients.filter(c => c !== res); }); return; } if (pathname === '/api/daily') { const date = url.searchParams.get('date') || new Date().toISOString().slice(0,10); const summary = queryDailySummary(date); const sessions = querySessionsByDate(date); const hist = queryHistoryForDate(date); res.writeHead(200, {'Content-Type':'application/json','Access-Control-Allow-Origin':'*'}); res.end(JSON.stringify({ date, summary, sessions, history: hist })); return; } if (pathname === '/api/export') { if (!db) { res.writeHead(500); res.end('no db'); return; } try { const rows = db.exec(`SELECT * FROM daily_summary ORDER BY date DESC LIMIT 365`); const cols = rows.length ? rows[0].columns : []; const data = rows.length ? rows[0].values.map(v => { const o={}; cols.forEach((c,i)=>o[c]=v[i]); return o; }) : []; res.writeHead(200, {'Content-Type':'application/json','Access-Control-Allow-Origin':'*'}); res.end(JSON.stringify({ daily: data, exported_at: new Date().toISOString() })); } catch(e) { res.writeHead(500); res.end(e.message); } return; } server.listen(PORT, '0.0.0.0', () = ...[truncated 2266 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/token-monitor.js:292
Finding

SQL Injection Through Unvalidated Date Parameters

Content
View full analysis
obj[c] = vals[i]); return obj; } } catch(e) {} return null; } function queryHistory(days, dateFilter) { if (!db) return []; try { const limit = Math.min(days * 24 * 60, 5000); let sql = "SELECT ts, date, rate_in, rate_out, rate_total, rate_cny, input_tokens, output_tokens, total_tokens FROM rate_history"; if (dateFilter) sql += " WHERE date = '" + dateFilter + "'"; sql += " ORDER BY ts DESC LIMIT " + limit; const rows = db.exec(sql); if (!rows.length) return []; const cols = rows[0].columns; return rows[0].values.map(v => { const o = {}; cols.forEach((c,i) => o[c] = v[i]); return o; }).reverse(); } catch(e) { return []; } } function querySessionsByDate(date) { if (!db) return []; try { const rows = db.exec(`SELECT session_key, model, kind, input_tokens, output_tokens, total_tokens, context_tokens, MAX(age_ms) as age_ms, COUNT(*) as snap_count FROM snapshots WHERE date = '${date}' GROUP BY session_key ORDER BY total_tokens DESC`); if (!rows.length) return []; const cols = rows[0].columns; return rows[0].values.map(v => { const o = {}; cols.forEach((c,i) => o[c] = v[i]); return o; }); } catch(e) { return []; } } if (pathname === '/api/daily') { const date = url.searchParams.get('date') || new Date().toISOString().slice(0,10); const summary = queryDailySummary(date); const sessions = querySessionsByDate(date); const hist = queryHistoryForDate(date); res.wri ...[truncated 2491 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/token-monitor.html:817
Finding

DOM-Based Cross-Site Scripting Through Unescaped Session Metadata

Content
View full analysis
暂无数据'; document.getElementById('t-count').textContent = '0 个会话'; return; } var rows = []; for (var k=0; k0?Math.round(inp/tot*100):0, outPct=100-inPct; rows.push('' + ''+(s.shortKey||s.session_key||s.key||'-').slice(-10)+''+ ''+(s.model||'-')+''+ ''+(s.kind||'-')+''+ ''+fmtN(inp)+''+ ''+fmtN(out)+''+ ''+fmtN(tot)+''+ '
'+ '
'+inPct+'% / '+outPct+'%
'+ ''+fmtN(ctx)+''+ ''+(s.timeStr||s.updated_at||'-')+''+ ''+(s.ageStr||fmtAge(s.ageMs||s.age_ms||0))+''); } tbody.innerHTML = rows.join(''); document.getElementById('t-count').textContent = sessions.length + ' 个会话'; window.__sessions = sessions; } ``` ### Technical Analysis The table r ...[truncated 1874 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
scripts/token-monitor.html:7
Finding

Remote Frontend Scripts Execute Without Subresource Integrity Controls

Content
View full analysis
``` ### Technical Analysis The dashboard loads executable JavaScript from jsDelivr at runtime. Although package versions are specified, the script tags do not include Subresource Integrity hashes. The browser therefore has no local cryptographic expectation for the fetched content. If the CDN, package artifact, account, DNS path, or delivery infrastructure is compromised, modified JavaScript executes in the dashboard's origin. Such code can access the same-origin monitoring APIs and all data exposed to the dashboard. The Google Fonts resources are not executable scripts, but they create unnecessary external connections that disclose client network metadata and increase the remote dependency surface. The Skill's core monitoring functionality does not require externally hosted fonts. ### Attack Path 1. An operator opens the monitoring dashboard. 2. The browser requests Chart.js and the zoom plugin from the external CDN. 3. A compromised delivery source returns modified JavaScript. 4. Because no integrity hash is supplied, the browser accepts and executes the modified response. 5. The script requests `/data`, `/api/daily`, or `/api/export` under the dashboard's origin. 6. The malicious dependency transmits collected telemetry to an attacker-controlled destination. ### Impact Assessment A successful supply-chain compromise grants attacker code t ...[truncated 429 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Output HandlingUnvalidated Output Injection, Cross-Context Output, Unbounded Output
  • Memory PoisoningPersistent Context Injection, Context Window Stuffing, Memory Manipulation
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (19)

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
- **前端**: `token-monitor.html`(Chart.js + chartjs-plugin-zoom,纯前端无需构建)

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The manifest description lists activation scenarios such as '用户要求查看 Token 消耗', '监控 AI 模型使用量', and '分析日/小时级别消耗趋势' without defining exact trigger phrases, exclusions, or contextual limits. These are broad natural-language intents that could match many ordinary analytics requests and cause unintended invocation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill explicitly documents permanent retention of token usage history in a local SQLite database, including session-level details, without any warning, consent flow, retention limit, or data minimization statement. Usage telemetry can reveal sensitive behavioral patterns, project activity, session identifiers, and potentially business-sensitive metadata, so silent indefinite storage increases privacy and insider-access risk.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This HTML document declares Chinese as the default language (lang="zh"), and the script also initializes LANG = 'zh', causing the interface to open in a specific locale by default. Although a language toggle exists later, the user is not offered an initial choice or opt-in before the Chinese locale is applied.

Content

No source excerpt is available for this finding.

Context Window Stuffing

Medium
Category
Memory Poisoning
Confidence
85% confidence
Finding

Skill attempts to fill the context window with filler content, displacing legitimate instructions and safety constraints. This can degrade agent performance or bypass safety boundaries.

Content

Scanner excerpt · scripts/token-monitor.html (reported line 373)May include surrounding context.

html
<div class="modal-stat"><div class="modal-stat-label">上下文窗口</div><div class="modal-stat-value purple" id="m-ctx">-</div></div>
          <div class="modal-stat"><div class="modal-stat-label">活跃时长</div><div class="modal-stat-value purple" id="m-age">-</div></div>
        </div>
        <div class="modal-bar" id="m-bar"><div class="modal-bar-fill input" id="m-bar-in"></div><div class="modal-bar-fill output" id="m-bar-out"></div></div>
        <div style="display:flex;justify-content:space-between;margin-top:4px"><span style="font-size:9px;color:#3b82f6" id="m-pct-in"></span><span style="font-size:9px;color:#10b981" id="m-pct-out"></span></div>
        <div class="modal-cny-note">&#128176; MiniMax 费用 = 输入&#215;¥2.1/&#x4E07; + 输出&#215;¥8.4/&#x4E07;</div>
      </div>

Context Window Stuffing

Medium
Category
Memory Poisoning
Confidence
85% confidence
Finding

Skill attempts to fill the context window with filler content, displacing legitimate instructions and safety constraints. This can degrade agent performance or bypass safety boundaries.

Content

Scanner excerpt · scripts/token-monitor.html (reported line 828)May include surrounding context.

html
<div class="modal-stat"><div class="modal-stat-label">上下文窗口</div><div class="modal-stat-value purple" id="m-ctx">-</div></div>
          <div class="modal-stat"><div class="modal-stat-label">活跃时长</div><div class="modal-stat-value purple" id="m-age">-</div></div>
        </div>
        <div class="modal-bar" id="m-bar"><div class="modal-bar-fill input" id="m-bar-in"></div><div class="modal-bar-fill output" id="m-bar-out"></div></div>
        <div style="display:flex;justify-content:space-between;margin-top:4px"><span style="font-size:9px;color:#3b82f6" id="m-pct-in"></span><span style="font-size:9px;color:#10b981" id="m-pct-out"></span></div>
        <div class="modal-cny-note">&#128176; MiniMax 费用 = 输入&#215;¥2.1/&#x4E07; + 输出&#215;¥8.4/&#x4E07;</div>
      </div>

Unbounded Output

Medium
Category
Output Handling
Confidence
80% confidence
Finding

Output size or generation rate is not bounded. Unbounded output enables denial-of-service through resource exhaustion, log flooding, or context-window stuffing.

Content

Scanner excerpt · scripts/token-monitor.html (reported line 373)May include surrounding context.

html
<div class="modal-stat"><div class="modal-stat-label">上下文窗口</div><div class="modal-stat-value purple" id="m-ctx">-</div></div>
          <div class="modal-stat"><div class="modal-stat-label">活跃时长</div><div class="modal-stat-value purple" id="m-age">-</div></div>
        </div>
        <div class="modal-bar" id="m-bar"><div class="modal-bar-fill input" id="m-bar-in"></div><div class="modal-bar-fill output" id="m-bar-out"></div></div>
        <div style="display:flex;justify-content:space-between;margin-top:4px"><span style="font-size:9px;color:#3b82f6" id="m-pct-in"></span><span style="font-size:9px;color:#10b981" id="m-pct-out"></span></div>
        <div class="modal-cny-note">&#128176; MiniMax 费用 = 输入&#215;¥2.1/&#x4E07; + 输出&#215;¥8.4/&#x4E07;</div>
      </div>

Unbounded Output

Medium
Category
Output Handling
Confidence
80% confidence
Finding

Output size or generation rate is not bounded. Unbounded output enables denial-of-service through resource exhaustion, log flooding, or context-window stuffing.

Content

Scanner excerpt · scripts/token-monitor.html (reported line 828)May include surrounding context.

html
<div class="modal-stat"><div class="modal-stat-label">上下文窗口</div><div class="modal-stat-value purple" id="m-ctx">-</div></div>
          <div class="modal-stat"><div class="modal-stat-label">活跃时长</div><div class="modal-stat-value purple" id="m-age">-</div></div>
        </div>
        <div class="modal-bar" id="m-bar"><div class="modal-bar-fill input" id="m-bar-in"></div><div class="modal-bar-fill output" id="m-bar-out"></div></div>
        <div style="display:flex;justify-content:space-between;margin-top:4px"><span style="font-size:9px;color:#3b82f6" id="m-pct-in"></span><span style="font-size:9px;color:#10b981" id="m-pct-out"></span></div>
        <div class="modal-cny-note">&#128176; MiniMax 费用 = 输入&#215;¥2.1/&#x4E07; + 输出&#215;¥8.4/&#x4E07;</div>
      </div>

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The comments at L0695-L0696 state live view uses delta per poll, and the dataset label at L0725 says 每次轮询增量. But the actual live-mode data at L0710-L0713 is computed as cumulative total_tokens minus the minimum total, which produces an accumulated curve rather than per-poll increments.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The page allows one-click export of usage history and cost data to CSV without any warning, confirmation, or data-minimization controls. In this monitoring context, exported records may contain sensitive operational metadata such as dates, usage volumes, and potentially session-linked identifiers, increasing the risk of accidental disclosure or mishandling.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The code hardcodes toLocaleTimeString('zh-CN', ...), which enforces a specific locale for displayed times. Under the policy, forcing a language or locale without user opt-in is a natural-language policy violation unless the constraint is clearly documented and justified.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

This timestamp display uses toLocaleTimeString('zh-CN', ...), imposing a Chinese locale in user-visible output. The file does not provide an opt-in, fallback to system locale, or explanation that would justify this locale restriction.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The script stores detailed session metadata, including session_key, model, kind, timestamps, token counts, and history, in a persistent SQLite database on disk. In the context of a monitoring tool, this creates a privacy and information-disclosure risk because local or remote consumers of the app can access operational metadata that may identify users, sessions, or usage patterns.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The /api/config endpoint allows any HTTP client to change POLL_INTERVAL without authentication or authorization. Because the server is also exposed over the network, a remote party can degrade service by forcing overly frequent polling or impair monitoring by setting long intervals, changing runtime behavior of the agent skill.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

Binding the HTTP server to 0.0.0.0 exposes monitoring and history endpoints to all reachable network clients, despite this being a local token-monitoring dashboard. The exposed APIs reveal session usage data and, combined with the unauthenticated config endpoint, expand the attack surface to remote users on the same network or any routed network.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
80% confidence
Finding

The manifest description and visible documentation are written entirely in Chinese, with no indication that users may choose another language or locale. Under the policy criteria, forcing a specific language without opt-in can be a natural-language policy concern.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The package description is written entirely in Chinese and provides no indication that users can choose another language or locale. Under the stated policy, forcing a specific language without opt-in is a natural-language policy concern.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The manifest explicitly describes 人民币费用估算(MiniMax 官方定价), suggesting pricing is scoped to MiniMax. However, the pricing table and model detection logic include GPT, Claude, DeepSeek, and Qwen models, extending behavior beyond the stated pricing basis.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
82% confidence
Finding

This code invokes a subprocess to collect session information, which is a safety-relevant operation under the rule set. While the command appears aligned with the monitor's purpose, there is no explicit user-facing notice, prompt, or descriptive comment near the execution point explaining that the script shells out to the openclaw CLI to gather active session data.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/token-monitor.js:302