Back to skill

Security audit

token-ledger

Security checks across malware telemetry and agentic risk

Overview

This is a disclosed local token ledger with a persistent watcher and Spark sync; the main risks are local privacy and background execution, not evidence of exfiltration or deception.

Install only if you are comfortable with a local background watcher reading OpenClaw session and cron usage logs and keeping a persistent SQLite ledger that includes session and chat/thread identifiers. Use one-shot mode instead of the LaunchAgent if you do not want continuous monitoring, and keep LOCAL_API_HUB_URL on a trusted loopback endpoint.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (7)

Tainted flow: 'req' from os.environ.get (line 414, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Content
url = f"{API_HUB_URL}/spark/token-log?limit=1000"
        req = urllib.request.Request(url, method="GET")
        req.add_header("Accept", "application/json")
        with urllib.request.urlopen(req, timeout=30) as resp:
            data = json.loads(resp.read().decode())
            if data.get("ok"):
                entries = data.get("entries", [])
Confidence
90% confidence
Finding
The watcher builds a request URL from the LOCAL_API_HUB_URL environment variable and performs an HTTP request without validating that the destination is limited to a trusted local endpoint. An attacker who can influence the process environment can redirect the watcher to an arbitrary host, causing unintended outbound requests and ingestion of attacker-controlled JSON into the ledger pipeline.

Lp3

Medium
Category
MCP Least Privilege
Confidence
87% confidence
Finding
The skill documentation describes capabilities to read and write local files, invoke shell commands, access environment variables, and perform network requests, but it does not declare corresponding permissions or prominently constrain them. Undeclared capabilities reduce user visibility and informed consent, making it easier for a skill to perform broader actions than a user expects.

Description-Behavior Mismatch

Medium
Confidence
77% confidence
Finding
This code adds HTTP-based Spark token retrieval to a watcher whose primary purpose is local log and SQLite accounting. That expands the attack surface by introducing network input and trust in external response data, which is materially riskier than purely local file parsing in an audit-grade ledger component.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The skill instructs users to install and load a LaunchAgent that persists as a background daemon and continuously processes files, but it does not provide an explicit warning that this creates ongoing background execution and persistent system changes. Users may unknowingly enable long-lived monitoring of session data and file writes, which has privacy and operational risk.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The watcher is described as tailing session and cron JSONL logs and synchronizing Spark usage through a local API, but the skill does not clearly disclose the privacy implications of continuously reading user activity logs and importing additional local usage data. Even if intended for accounting, this expands data collection beyond a simple report generator and can expose sensitive prompts, metadata, or operational patterns.

Context Leakage

High
Category
Data Exfiltration
Content
m_chat = _re.search(r'discord:channel:(\d+)', sk)
        if m_chat: chat_id = m_chat.group(1)

        # Extract thread_id from session key like "...:topic:1479712989392273498"
        m_thread = _re.search(r':topic:(\d+)', sk)
        if m_thread: thread_id_meta = m_thread.group(1)
Confidence
75% confidence
Finding
The watcher extracts and stores chat_id and thread_id from session metadata into the ledger, which increases the amount of user/context linkage retained in a financial audit database. In this skill context, the ledger is intended for token accounting, so persisting communication identifiers creates unnecessary correlation risk if the database is accessed or shared.

Context Leakage

High
Category
Data Exfiltration
Content
# Strip .jsonl and any .deleted* / .reset* suffix
    full_stem = basename.split(".jsonl")[0]

    # Extract thread_id from -topic- suffix
    # e.g. "a2c6e616-...-topic-1477936395443245127"
    topic_match = _re.search(r'-topic-(\d{17,20})$', full_stem)
    if topic_match:
Confidence
75% confidence
Finding
This path-based fallback extracts thread identifiers directly from filenames and propagates them into the ledger, again widening contextual data retention beyond raw token counts and cost. Because this is an audit-grade ledger, retaining stable conversation identifiers can expose activity mapping and user relationships if the database is later queried by other tools or compromised.

VirusTotal

65/65 vendors flagged this skill as clean.

View on VirusTotal

Static analysis

Detected: suspicious.dynamic_code_execution

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
scripts/test_price_versions.py:16