Back to skill

Security audit

workled

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly coherent for controlling a workled device, but it installs persistent agent hooks and supports password-typing macros over an apparently unauthenticated HTTP device endpoint.

Install only if you trust the device and local network, review the exact client selected by --client, and avoid password macros unless the device transport is protected and you are certain about physical security and input focus. Be especially cautious before approving sudo/UAC elevation for dsh installation.

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
references/macro_format.md:82
Finding

Plaintext unauthenticated MCP transport exposes password-bearing HID macro configuration

Content
View full analysis

Vulnerability Details

File Location: references/macro_format.md:82-85
Related Locations: references/device_setup.md:34-50, SKILL.md:23, index.js:915-925, dsh-plugin/patch.yml:10
Vulnerability Type: Plaintext transmission of sensitive data and unauthenticated device control
Risk Level: High

Complete Evidence

references/macro_format.md:82-85 documents sending a plaintext password as part of a macro:

markdown
### password

Type a password stored in encrypted hardware NVS. Stored/queried macros show
`*` of identical length.

- `{"password": "Abc123"}` — plain password

references/device_setup.md:34-50 directs clients to use an unencrypted HTTP MCP endpoint without documenting authentication:

markdown
## MCP endpoint

Once the device is on the same network, its MCP endpoint is:

http://<device-name>.local:18791/mcp

text

Add the server to your agent config. For opencode, edit `~/.config/opencode/opencode.json`:

```jsonc
{
  "mcp": {
    "workled": {
      "type": "remote",
      "url": "http://&lt;device-name&gt;.local:18791/mcp",
      "enabled": true
    }
  }
}

SKILL.md:23 exposes the macro mutation operation:

markdown
| set_macro | macro_name: string, macro_json: string | Set the macro for a touch pad gesture; macro_name ∈ `single_click`/`double_click`/`long_press`; macro_json is a JSON array of segments (see Macro Format); empty macro_json resets | `set_macro("single_click", '[{"combo":"ctrl+c"}]')` |

The bundled client’s request implementation in index.js:915-925 supplies content negotiation headers but no authentication credentials:

javascript
async function postJson(url, method, params, controller, extraHeaders = {}) {
  const res = await fetch(url, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Accept: "application/json",
      ...extraHeaders,
    
...[truncated 3410 chars]
Remediation
View remediation

Remediation Suggestions

  1. Require HTTPS for the MCP endpoint and validate the device certificate or a pinned device identity.
  2. Require per-device authentication for every MCP request, especially set_macro and other state-changing tools. Use a securely provisioned token, mutual TLS, or a cryptographic challenge-response protocol.
  3. Do not provision reusable passwords as plaintext JSON fields over the network. Prefer device-local secret enrollment or application-specific tokens with restricted scope.
  4. If remote secret provisioning is unavoidable, encrypt the secret for the authenticated device before transmission and prevent it from appearing in agent transcripts, logs, diagnostics, or error messages.
  5. Separate low-risk LED-state operations from sensitive HID macro administration. Apply stronger authorization and explicit user confirmation to macro changes.
  6. Bind the device management endpoint to trusted interfaces and reject requests from unauthenticated LAN clients.
  7. Update references/device_setup.md, references/macro_format.md, and generated client configurations so insecure HTTP password provisioning is not presented as the default workflow.
  8. Add integration tests verifying that unauthenticated macro mutation is rejected and that password-bearing requests cannot be sent over plaintext transport.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
Findings (31)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The reported implementation goes beyond LED control into reading Windows registry-backed environment variables, probing filesystem write access, manipulating app config directories, creating symlinks/junctions, and parsing JSONC. Those host-level operations are significantly more privileged than the declared purpose and can be abused to modify execution paths, redirect resources, or create persistence footholds if performed unsafely.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The reported implementation goes beyond LED control into reading Windows registry-backed environment variables, probing filesystem write access, manipulating app config directories, creating symlinks/junctions, and parsing JSONC. Those host-level operations are significantly more privileged than the declared purpose and can be abused to modify execution paths, redirect resources, or create persistence footholds if performed unsafely.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The reported implementation goes beyond LED control into reading Windows registry-backed environment variables, probing filesystem write access, manipulating app config directories, creating symlinks/junctions, and parsing JSONC. Those host-level operations are significantly more privileged than the declared purpose and can be abused to modify execution paths, redirect resources, or create persistence footholds if performed unsafely.

Content

No source excerpt is available for this finding.

MCP Config Access

High
Category
Agent Snooping
Confidence
90% confidence
Finding

Skill accesses MCP server configuration files (mcp.json). MCP configs contain server URLs, authentication tokens, and tool definitions — reading them allows the skill to discover and potentially abuse other tool integrations.

Content

Scanner excerpt · skill-install.mjs (reported line 973)May include surrounding context.

js
const core = /\s/.test(entry) ? `"${entry}"` : entry;
  let cmd = `node ${core} hook --event ${eventName} --client ${client}`;
  // The hook discovers the MCP URL at runtime from its own configuration
  // (mcp.json / WORKLED_MCP_URL), so no --url is inlined here. This keeps the
  // command stable across installs and avoids any shell/sandbox mangling of the
  // URL argument. The `url` parameter is accepted for call compatibility but is
  // intentionally unused by the generated command.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The installer can re-execute itself via PowerShell RunAs or sudo to obtain elevated privileges, despite the skill's purpose being device-state synchronization and effect configuration. Privilege escalation dramatically increases the consequences of any bug, path mistake, or future compromise because the script can then alter protected system/user files outside the original sandbox or permission context.

Content

No source excerpt is available for this finding.

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
80% 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 · test/dsh-roundtrip.mjs (reported line 6)May include surrounding context.

js
//
// WARNING: this drives the real installer against the real dsh home
// (~/.dsh on unix, %LOCALAPPDATA%\dsh on Windows). It snapshots and restores
// cordis.patch.yml and the bundle, but it does create and delete
// profiles/web/node_modules/workled along the way — so it needs a sandbox that
// permits deleting under the dsh home. It is deliberately NOT part of `npm
// test` (which only runs the hermetic unit/install suites).

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
80% 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 · test/install.test.mjs (reported line 251)May include surrounding context.

js
//
// The user can write `"workled":\n  { ... }` with the `{` on a separate line.
// `findKeyLineStartForValue` must walk back from the `{` and return the
// OPENING quote of the key string, not the closing quote — otherwise remove
// surgery leaves half the key behind and the JSON becomes invalid.
test("findKeyLineStartForValue returns opening quote on key+value cross-line layout", () => {
  const text = `{

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
84% confidence
Finding

The skill declares MCP tools and troubleshooting commands but does not declare any explicit tool scope despite static analysis indicating environment and network capabilities. Missing scope boundaries weakens least-privilege controls and can let a seemingly simple device-control skill access broader resources than users would reasonably expect.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The provided skill-manifest context describes a skill whose agent states and configuration are exposed over MCP. In contrast, the package description explicitly says the plugin listens to agent events and drives the workled device directly over HTTP, which is a materially different integration model and expands behavior beyond the stated MCP-only framing.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The plugin performs outbound HTTP POST requests to a fully configurable URL derived from environment/config, which creates a server-side request capability and transmits agent activity metadata off-process. In this skill context, network communication to a workled MCP endpoint is expected, but the lack of destination restriction, scheme validation, or explicit disclosure means a misconfigured or malicious URL could redirect state telemetry to arbitrary internal or external services.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The skill performs host Bluetooth inspection that goes beyond its core purpose of syncing agent state to a workled device over MCP. It enumerates local Bluetooth adapter state and paired device names, which exposes host-environment information and hardware inventory without clear necessity for the primary LED-sync function, increasing privacy and local reconnaissance risk.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The Bluetooth diagnostic logic spawns platform-specific subprocesses such as PowerShell, blueutil, system_profiler, and bluetoothctl to inspect the local system. Even though the commands are hardcoded, this materially expands the skill's host interaction surface and can reveal local configuration details or create unexpected side effects in restricted environments.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
75% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

Scanner excerpt · references/device_setup.md (reported line 195)May include surrounding context.

md
- **Device reachable but something looks off** — `index.js status` prints a `hint`; follow its ordered checklist (`LED → MCP → trust → hooks → DNS`):
  1. **LED** — brightness may be 0; run `set_brightness(128)`, or use the device's manual on/off switch.
  2. **MCP** — the config was just added/edited; **restart the agent or the session** so it reloads the new MCP server entry.
  3. **trust** — some agents require **manually trusting/allowing** the MCP connection before they will use it. Without approval the server is configured but never connected.
  4. **hooks** — some agents need to **manually enable lifecycle hooks** (e.g. `Settings → Hooks`) for the auto `set_agent_state` to fire.
  5. **DNS** — on Windows mDNS (`.local`) is unstable under load; in the MCP config prefer a **static IP** over the `.local` hostname to avoid intermittent `-32001` timeouts.
- **No MCP config found at all** — neither `WORKLED_MCP_URL` nor any config

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The documentation exposes a capability to inject stored passwords into the host via HID macros without an explicit warning about target verification, unintended focus, or credential handling risk. In this skill’s context, the device can automatically type secrets into whatever window is active, which creates a realistic risk of accidental credential disclosure or misuse if macros are triggered on the wrong host or at the wrong time.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The Windows unlock example operationalizes credential injection for workstation unlocking and provides a ready-made pattern for typing a stored password into the host. This is more dangerous than generic macro documentation because it encourages a sensitive authentication workflow without warning about misfires, wrong-device targeting, active-window spoofing, or unauthorized physical use of the device.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
87% confidence
Finding

The installer sets up persistent lifecycle hooks that execute on user prompts, notifications, tool events, and session boundaries. Persistent automatic execution on future sessions materially increases risk because the skill remains active beyond the initial install and can observe or influence ongoing agent workflows without further per-use consent.

Content

Scanner excerpt · skill-install.mjs (reported line 983)May include surrounding context.

js
// Each lifecycle event the workled hook should fire on. `matcher` (only for
// PreToolUse/PostToolUse/Notification) restricts the hook so it does NOT run on
// every tool call — a bare PreToolUse hook would spawn a ~3.6s process per
// Bash/Read/Write and stall the agent.
//
// AskUserQuestion timing (WorkBuddy/CodeBuddy, verified in index.js): the host
// fires PreToolUse AND PostToolUse for AskUserQuestion at the correct moments

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The installer modifies multiple host/client configuration files, installs plugins/hooks, writes MCP entries, and manages skill directories across several clients, which materially exceeds the narrow skill description of syncing agent states to a light device over MCP. Even if intended for convenience, this broad persistence and cross-client reconfiguration increases the attack surface and gives the skill long-lived control over agent lifecycle events and local developer tooling.

Content

No source excerpt is available for this finding.

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 · skill-install.mjs (reported line 1444)May include surrounding context.

js
//   object -> parsed config
//   null   -> file exists but is unparseable
// `null` must never be treated as "no workled entries": both install and
// uninstall write the object back WHOLE, so an empty fallback would replace the
// user's entire config (agents/models/... measured 346 lines on this machine)
// with a stub. Callers refuse to write instead - see skippedOpenclawConfig().
function readOpenclawConfig() {

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 · skill-install.mjs (reported line 1613)May include surrounding context.

js
if (!hasWorkled) return msg.trimEnd() || `No openclaw workled plugin installed`;
  }

  // Gateway didn't stabilise — force-write clean config one final time. Skip the
  // write (but keep the report) if the file became unparseable in the meantime.
  const again = readOpenclawConfig();
  if (again !== null) {

Unbounded Resource Access

Medium
Category
Excessive Agency
Confidence
75% confidence
Finding

Skill allows unbounded resource consumption (API calls, storage, compute). Without rate limits or quotas, a compromised or misbehaving agent can cause denial-of-service or cost overruns.

Content

Scanner excerpt · skill-install.mjs (reported line 2349)May include surrounding context.

js
function runElevated() {
  const self = fileURLToPath(import.meta.url);
  const args = [self, ...process.argv.slice(2)];
  // WORKLED_ELEVATED marks the child so a second failure cannot loop forever.
  const childEnv = { ...process.env, WORKLED_ELEVATED: "1" };

  if (process.platform === "win32") {

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
98% confidence
Finding

The script invokes sudo to rerun itself with elevated privileges. Even when meant to help installation, embedding root execution in a general-purpose skill installer is dangerous because it expands trust from user-level config edits to privileged code execution, enabling severe damage if the script or its inputs are ever abused.

Content

Scanner excerpt · skill-install.mjs (reported line 2381)May include surrounding context.

js
const r = spawnSync("sudo", [process.execPath, ...args], { stdio: "inherit", env: childEnv });
  if (r.error) {
    console.error(
      `workled: could not re-run through sudo (${r.error.message}).\n` +
        `  Re-run manually with enough privileges:\n` +
        `    sudo ${[process.execPath, ...args].map((a) => JSON.stringify(a)).join(" ")}`
    );

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · skill-install.mjs (reported line 2383)May include surrounding context.

js
console.error(
      `workled: could not re-run through sudo (${r.error.message}).\n` +
        `  Re-run manually with enough privileges:\n` +
        `    sudo ${[process.execPath, ...args].map((a) => JSON.stringify(a)).join(" ")}`
    );
    return false;
  }

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding

npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding

npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding

npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.dangerous_exec, suspicious.env_credential_access

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
skill-install.mjs:2511

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
test/dsh-loader-trace.mjs:41

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
test/dsh-roundtrip.mjs:47

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
index.js:237