Back to skill

Security audit

Clawctl

Security checks for vulnerabilities and agentic risk

Overview

This coordination skill is coherent overall, but its dashboard exposes a persistent token-bearing web UI on all network interfaces with task mutation authority, so it needs Review before installation.

Review this skill before installing if you intend to use the dashboard. Prefer running it only on localhost, avoid sharing token URLs, rotate or delete ~/.openclaw/.clawctl-token if exposed, and treat the local SQLite database as containing task, message, and activity history for all participating agents.

Vulnerability Patterns
  • 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
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (3)

T09 · Insecure Skill Coding Practices

Error
Location
dashboard/server.py:151
Finding

Network-Exposed Dashboard Uses a Bearer Token in Cleartext URLs

Content
View full analysis
:{args.port}/?token={TOKEN}") print(f"\n Token: {TOKEN}") print(f"\n{'=' * 50}\n") app.run(host="0.0.0.0", port=args.port, threaded=True) ``` ```javascript const state = { tasks: [], agents: [], selectedTask: null, token: new URLSearchParams(location.search).get('token'), sseRetries: 0, eventSource: null, effectsOn: localStorage.getItem('cc_effects') === 'true', matrixRaf: null, sheetFocusTrap: null, previousFocus: null, }; const api = { async get(endpoint) { const res = await fetch(`${endpoint}?token=${state.token}`); if (res.status === 401) throw new Error('Unauthorized'); if (!res.ok) throw new Error(`API error: ${res.status}`); return res.json(); }, async post(endpoint, body = {}) { const res = await fetch(`${endpoint}?token=${state.token}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) }); if (res.status === 401) throw new Error('Unauthorized'); if (!res.ok) throw new Error(`API error: ${res.status}`); return res.json(); } }; ``` ```javascript const es = new EventSource(`/api/heartbeat?token=${state.token}`); ``` ### Technical Analysis The Flask server listens on `0.0.0.0`, making the dashboard reachable through every availab ...[truncated 2398 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
dashboard/server.py:20
Finding

Dashboard Token File Is Created Without Explicit Owner-Only Permissions

Content
View full analysis
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
dashboard/index.html:9
Finding

Unpinned Third-Party CDN Script Executes in the Authenticated Dashboard

Content
View full analysis
``` ### Technical Analysis The dashboard executes JavaScript directly from a third-party CDN at runtime. The URL does not identify a fixed reviewed version and does not use Subresource Integrity. Remote JavaScript executes with the same origin privileges as the dashboard's own code. It can inspect `location.search`, where the dashboard stores its persistent bearer token, read API responses and locally cached board data, invoke authenticated endpoints, and transmit captured information to an external server. No restrictive Content Security Policy is shown that would meaningfully constrain the remote script. Therefore, a CDN compromise, upstream account compromise, malicious update, or unexpected behavioral change would affect every dashboard load without requiring a new release of this project. ### Attack Path 1. An attacker compromises the CDN distribution path, the upstream asset, or an account controlling the served script. 2. A dashboard user loads `index.html`. 3. The browser downloads and executes the altered script from `cdn.tailwindcss.com`. 4. The script reads the bearer token from `location.search` and accesses dashboard data in the page or through authenticated API calls. 5. The script transmits the token or fleet data to attacker-controlled infrastructure. 6. The attacker reuses the token to access the dashboard and invoke its mutation endpoints. ### Impact Assessment Successful supply-chain exploitation can disclose the dashboard bearer token and all data available to the authenticated page. It can also perform dashboard actions in the user's browser or enable subsequent unauthorized API access. The immediate privilege is control within the dashboard origin rather than native operating-system execut ...[truncated 126 chars]
Remediation
View remediation
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
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
Findings (26)

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
85% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · CLAUDE.md (reported line 27)May include surrounding context.

CLAW_DB=/tmp/test.db .venv/bin/clawctl add "Test task" -p 1 CLAW_DB=/tmp/test.db CLAW_AGENT=agent1 .venv/bin/clawctl claim 1 CLAW_DB=/tmp/test.db .venv/bin/clawctl board rm -f /tmp/test.db

text

Always use `CLAW_DB=/tmp/test.db` to avoid touching the real database at `~/.openclaw/clawctl.db`.

Session Persistence

Medium
Category
Rogue Agent
Confidence
72% confidence
Finding

The documentation states that a persistent auth token is saved to ~/.openclaw/.clawctl-token, which introduces session persistence on disk. If that token is stored without strict file permissions, rotation, expiration, or secure storage guarantees, another local process or user on the same system could reuse it to access or act through the dashboard session.

Content

Scanner excerpt · CLAUDE.md (reported line 38)May include surrounding context.

md
- **`clawctl/db.py`** — All SQL lives here. Every query uses `?` parameterized placeholders. Mutating functions return `(ok: bool, payload)` tuples. The `get_db()` context manager handles commit/rollback/close. This module is imported by both the CLI and the Flask server.
- **`clawctl/cli.py`** — Click commands. Each subcommand is a thin wrapper that calls `db.*` functions and formats output. The `print_columnar()` helper handles aligned table output with Unicode-aware width calculation.
- **`clawctl/schema.sql`** — Loaded by `db.init_db()` via `Path(__file__).parent`. Uses `CREATE TABLE IF NOT EXISTS` so re-running init is safe.
- **`dashboard/server.py`** — Flask app that imports `clawctl.db`. Read-only except for claim/complete endpoints. Persistent auth token saved to `~/.openclaw/.clawctl-token`. Not part of the installable package.
- **`dashboard/index.html`** — Single-file vanilla JS web UI. Tailwind via CDN. SSE for live updates.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The documentation first advertises 'Complete and delete actions from the UI' and then states 'The dashboard is read-mostly' and that 'The CLI is the primary interface; the dashboard is for monitoring.' Those statements actively pull in different directions because the dashboard is documented as performing task mutations, not just monitoring.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding

The skill invokes a local CLI, relies on environment variables, and implicitly requires filesystem and shell access, but it does not declare any tool scope or permission boundaries. In an agent environment, this can cause the skill to run with broader capabilities than operators expect, increasing the chance of unintended command execution or access to local files and environment data.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
80% confidence
Finding

The skill instructs the agent to create and use a persistent local database and to store identity information in environment variables across sessions. Persistent state can retain task history, messages, and agent identifiers that may be sensitive, and if the database path or file permissions are not constrained, other local users or processes could read or tamper with that state.

Content

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

Setup

bash
clawctl init                        # create the database
export CLAW_AGENT=your-name         # set identity (falls back to $USER with warning)
export CLAW_DB=~/.openclaw/clawctl.db  # optional, this is the default

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · clawctl/cli.py (reported line 125)May include surrounding context.

python
@click.option("--for", "assignee", default="", help="Assign to agent")
@click.option("--parent", type=int, default=None, help="Parent task ID")
def add(subject, desc, priority, assignee, parent):
    """Create a task"""
    with db.get_db() as conn:
        ok, task_id = db.add_task(
            conn, subject, desc, priority, assignee, db.AGENT, parent

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
85% confidence
Finding

The stop path trusts a PID loaded from a writable pid file and calls os.kill(pid, SIGTERM) without verifying that the PID belongs to the dashboard process. If an attacker or another local user/process can alter that pid file, the CLI can be tricked into terminating an unintended local process under the current user's privileges.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · clawctl/cli.py (reported line 489)May include surrounding context.

python
stdout_target = subprocess.DEVNULL
        stderr_target = subprocess.DEVNULL

    proc = subprocess.Popen(
        [sys.executable, "-m", "dashboard", "--port", str(port)],
        stdout=stdout_target,
        stderr=stderr_target,

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The command prints a fully authenticated localhost URL containing the dashboard token directly to stdout. Tokens echoed to terminals can be captured by shell history tools, terminal logging, scrollback sharing, screenshots, or wrapper systems, which can expose dashboard access to unintended parties.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The bulk mark-as-read path updates messages by arbitrary ID only and does not constrain the update to messages addressed to the requesting agent. Any caller able to invoke this function can mark other agents' messages as read, undermining message integrity and hiding unread alerts or coordination items.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The dashboard exposes a destructive delete action that executes immediately when clicked, with no confirmation dialog, undo flow, or other user-facing safeguard. In a coordination console for agent fleets, accidental taps/clicks on mobile or during rapid task triage can cancel or remove active work, causing operational disruption and possible loss of task state.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The application claims token auth, but the root page is explicitly exempted from authentication while the main URL printed to users includes the token in the query string. This can mislead operators into believing the whole dashboard is protected, and exposing the entry page unauthenticated can aid discovery, leak client-side logic, and encourage unsafe token handling via URLs that may be logged, cached, or shared.

Content

No source excerpt is available for this finding.

Tainted flow: 'token' from pathlib.Path.read_text (line 23, file read) → pathlib.Path.write_text (file write)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · dashboard/server.py (reported line 27)May include surrounding context.

python
if token:
            return token
    token = secrets.token_urlsafe(16)
    TOKEN_PATH.write_text(token)
    return token

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The /api/task/int:task_id/delete endpoint performs a destructive operation by canceling/deleting a task, but there is no confirmation prompt, user-facing warning, or explanatory comment/docstring indicating that this action is irreversible or safety-relevant. In a code file, destructive operations should have some visible disclosure unless the warning is provided elsewhere in markdown documentation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The markdown includes rm -f /tmp/test.db, which is a destructive operation that deletes a file. Although it is part of test cleanup, the document does not explicitly warn the user that this command removes the temporary database file.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

The README advertises "Complete and delete actions from the UI" but does not warn users that the dashboard can perform destructive task deletions. For markdown files, actions that can affect user data or system integrity should be accompanied by a clear warning or disclosure.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
73% confidence
Finding

When verbose logging is enabled, dashboard stdout and stderr are appended to a persistent log file without warning about potentially sensitive contents. If the dashboard emits tokens, message bodies, task metadata, or other internal state, those secrets may remain on disk longer than intended and be readable by other local principals depending on file permissions.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Low
Category
Not specified by scanner
Confidence
69% confidence
Finding

The skill description emphasizes coordination, messaging, activity feed, and dashboard functions, but this file implements direct subprocess launching with subprocess.Popen. Although related to the dashboard feature, process spawning is a privileged host capability that is stronger than ordinary coordination/data operations and is not otherwise constrained here.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Low
Category
Not specified by scanner
Confidence
83% confidence
Finding

The manifest describes a coordination layer for fleet tasks, messaging, activity feed, and dashboard features. Reading process environment variables for identity and storage location is an extra capability that is not evident from that purpose alone, especially deriving agent identity from USER/CLAW_AGENT rather than from explicit function inputs.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
74% confidence
Finding

The module reads CLAW_DB, CLAW_AGENT, and USER from the environment to determine database location and agent identity. Accessing environment-derived identity information can affect attribution and privacy, but the file does not disclose this behavior beyond raw assignment statements.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
82% confidence
Finding

The init_db function creates a directory, opens a SQLite database, and executes a schema script, which are file-system write operations. Although the module docstring describes return conventions, there is no user-facing warning, print/log message, or comment near this operation disclosing that local files and directories will be created or modified.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
76% confidence
Finding

Functions such as add_task store task subject and description, and other functions later persist notes, messages, and activity metadata to the local database. These are file-write operations affecting user data, but this file provides no comments, docstrings, or user-visible logging around that persistence behavior.

Content

No source excerpt is available for this finding.

Unverifiable Dependency: setuptools has 10 known advisory(ies) (CVE-2013-1633 (Setuptools vulnerable to Man-in-the-middle attacks); CVE-2025-47273 (setuptools has a path traversal vulnerability in PackageIndex.download that lead); CVE-2024-6345 (setuptools vulnerable to Command Injection via package URL) +7 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Content

No source excerpt is available for this finding.

Unverifiable Dependency: click has 1 known advisory(ies) (CVE-2026-7246 (Pallets Click, versions 8.3.2 and below, contain a command injection vulnerabili)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
94% confidence
Finding

The unpinned flask dependency is more concerning in context because this skill includes a dashboard package and describes messaging/activity-feed coordination, implying network-facing or web-exposed functionality. If dependency resolution selects a Flask version affected by one of its known advisories, the application could inherit denial-of-service, session/key-handling, or other web security weaknesses.

Content

No source excerpt is available for this finding.

Unverifiable Dependency: flask has 10 known advisory(ies) (CVE-2025-47278 (Flask uses fallback key instead of current signing key); CVE-2018-1000656 (Flask is vulnerable to Denial of Service via incorrect encoding of JSON data); CVE-2019-1010083 (Pallets Project Flask is vulnerable to Denial of Service via Unexpected memory u) +7 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
94% confidence
Finding

The unpinned flask dependency is more concerning in context because this skill includes a dashboard package and describes messaging/activity-feed coordination, implying network-facing or web-exposed functionality. If dependency resolution selects a Flask version affected by one of its known advisories, the application could inherit denial-of-service, session/key-handling, or other web security weaknesses.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.