Back to skill

Security audit

Mqtt Client

Security checks for vulnerabilities and agentic risk

Overview

This MQTT automation skill is mostly coherent, but it needs review because it can handle credentials and persistent configuration in ways that may silently weaken or redirect secure connections.

Review before installing. Use only least-privilege MQTT accounts, avoid the `#` wildcard except on trusted scoped brokers, do not run it from untrusted project directories, secure `~/.openclaw/openclaw.json` permissions, and prefer a pinned dependency plus a fix for TLS certificate verification before using it with real credentials.

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 (4)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/mqtt-client.js:239
Finding
TLS Certificate Verification Is Disabled by Default<![CDATA[ ## Vulnerability Details **File Location**: `scripts/mqtt-client.js`, lines 239-246 **Vulnerability Type**: Improper certificate validation **Risk Level**: High ### Vulnerable Code ```javascript const opts = { clientId: this.options.clientId, reconnectPeriod: this.options.reconnectPeriod, connectTimeout: this.options.connectTimeout, keepalive: this.options.keepalive, clean: true, rejectUnauthorized: false }; ``` ### Technical Analysis The MQTT client unconditionally sets `rejectUnauthorized` to `false`. For TLS-based MQTT connections such as `mqtts://` or secure WebSocket connections, this directs the underlying TLS implementation to accept certificates that cannot be validated against a trusted certificate authority. This disables server authentication and allows self-signed, expired, mismatched, or attacker-controlled certificates to be accepted without warning. Although the project advertises TLS support, encryption without certificate verification does not protect against an active man-in-the-middle attacker. The setting is applied to all connections and cannot be securely overridden through the documented constructor configuration because it is hardcoded in the generated client options. ### Attack Path 1. A victim configures the client to connect to a TLS-enabled MQTT broker. 2. The attacker obtains a network position through a malicious Wi-Fi access point, DNS poisoning, routing manipulation, or a compromised proxy. 3. The attacker redirects the connection to a broker or TLS proxy under their control. 4. The attacker presents a forged or self-signed certificate. 5. The client accepts the certificate because `rejectUnauthorized` is disabled. 6. The client transmits MQTT credentials and traffic through the attacker-controlled endpoint. 7. The attacker can inspect messages, capture credentials, alter published control commands, or inject fabricated broker messages. ### Impact Assessment An attacker with a suitable network posit ...[truncated 486 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Set `rejectUnauthorized` to `true` by default. - Permit certificate verification to be disabled only through an explicit, clearly named development-only option. - Support trusted custom certificate authorities through options such as `ca`, `cert`, and `key`. - Validate that TLS-specific settings are used only with secure MQTT protocols. - Document the risks of disabling certificate verification. - Add automated tests confirming that untrusted, expired, and hostname-mismatched certificates are rejected. A safer implementation would resemble: ```javascript const opts = { clientId: this.options.clientId, reconnectPeriod: this.options.reconnectPeriod, connectTimeout: this.options.connectTimeout, keepalive: this.options.keepalive, clean: true, rejectUnauthorized: this.options.rejectUnauthorized !== false }; if (this.options.ca) opts.ca = this.options.ca; if (this.options.cert) opts.cert = this.options.cert; if (this.options.key) opts.key = this.options.key; ``` ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/mqtt-client.js:135
Finding
Untrusted Working-Directory Configuration Can Redirect MQTT Credentials<![CDATA[ ## Vulnerability Details **File Location**: `scripts/mqtt-client.js`, lines 135-163 and 245-273 **Vulnerability Type**: Unsafe configuration discovery and credential redirection **Risk Level**: High ### Vulnerable Code ```javascript const possiblePaths = [ path.join(process.env.HOME || process.env.USERPROFILE, '.openclaw', 'openclaw.json'), path.join(process.cwd(), 'openclaw.json'), path.join(process.cwd(), '.openclaw', 'openclaw.json'), path.join(__dirname, '..', '..', 'openclaw.json') ]; for (const configPath of possiblePaths) { try { if (fs.existsSync(configPath)) { const config = JSON.parse(fs.readFileSync(configPath, 'utf8')); // FIX: Use correct path const env = config.skills?.entries?.['mqtt-client']?.env; if (env) { this._log('debug', `Loaded config from ${configPath}`); return { broker: env.MQTT_BROKER, port: parseInt(env.MQTT_BROKER_PORT) || 1883, username: env.MQTT_USERNAME, password: env.MQTT_PASSWORD, clientId: env.MQTT_CLIENT_ID, protocolVersion: parseInt(env.MQTT_PROTOCOL_VERSION) || 4, subscribeTopic: env.MQTT_SUBSCRIBE_TOPIC }; } } } catch { // Ignore errors, continue to next path } } ``` ```javascript // Credentials if (this.options.username) opts.username = this.options.username; if (this.options.password) opts.password = this.options.password; // LWT if (this.options.will) opts.will = this.options.will; // TLS if (this.options.tls) opts.tls = this.options.tls; // MQTT 5.0 Properties if (this.options.properties) opts.properties = this.options.properties; // Protocol Version (4 = MQTT 3.1.1, 5 = MQTT 5.0) if (this.options.protocolVersion) opts.protocolVersion = this.options.protocolVersion; // Override with openclaw.json if present const openclawConfig = this._loadOpenClawConfig(); if (openclawConfig.broker) this.options.broker = openclawConfig.broker; if (openclawConfig.port) t ...[truncated 2781 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Remove current-working-directory paths from automatic configuration discovery. - Use one canonical, explicitly documented configuration path. - Make explicit constructor options take precedence over environment variables and files. - Resolve the broker and its credentials from the same trusted configuration source. - Require explicit approval before combining credentials from one source with a destination from another. - Verify configuration file ownership and reject files writable by unauthorized users. - Avoid silently swallowing parse and permission errors; return actionable security errors. - Validate broker protocols and require TLS with certificate verification when credentials are present. - Consider allowing callers to pass an explicit configuration path rather than searching implicitly. ]]>

T08 · Insecure Dependencies

Warning
Location
SKILL.md:18
Finding
Runtime Dependency Is Installed Without Version or Integrity Pinning<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 18-22 **Vulnerability Type**: Unpinned third-party dependency **Risk Level**: Medium ### Vulnerable Code ```markdown ### Prerequisites ```bash npm install mqtt ``` ``` The same unpinned instruction also appears in `README.md`, lines 16-20: ```markdown ## Quick Start ```bash npm install mqtt ``` ``` ### Technical Analysis The installation instructions request the `mqtt` package without an exact version. npm will resolve the package and its transitive dependency graph according to the state of the registry at installation time. The package name is consistent with the documented mqtt.js project, so no typosquatting claim is established. Nevertheless, the absence of an exact version, lockfile, and recorded integrity data makes installations non-reproducible. A future compromised, malicious, or incompatible package release would be trusted automatically by users following the documented setup process. No project `package.json` or lockfile is present in the audited directory, so the project does not establish an auditable dependency baseline. ### Attack Path 1. A future release of the `mqtt` package or one of its transitive dependencies is compromised. 2. A user follows the documented `npm install mqtt` instruction. 3. npm resolves the compromised release because no audited version is pinned. 4. Package installation hooks or subsequently imported runtime code execute with the privileges of the user running the application. 5. The compromised dependency can access process environment variables, MQTT credentials, local files available to the process, and network resources. ### Impact Assessment Successful exploitation can result in arbitrary code execution with the privileges of the user installing or running the skill. This may expose MQTT credentials, OpenClaw configuration, user-readable files, and accessible network services. The issue does not itself prove that the current upstre ...[truncated 135 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Add a `package.json` that pins an audited exact version of `mqtt`. - Commit a generated `package-lock.json` containing resolved versions and integrity hashes. - Recommend `npm ci` instead of an unconstrained `npm install`. - Use automated dependency scanning and update dependencies through reviewed pull requests. - Review package lifecycle scripts and consider disabling them where operationally possible. - Document the tested Node.js and mqtt.js versions. - Periodically audit transitive dependencies and promptly address published security advisories. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/mqtt-client.js:1248
Finding
Module Import Mutates User Configuration and May Create a Plaintext Credential File with Permissive Permissions<![CDATA[ ## Vulnerability Details **File Location**: `scripts/mqtt-client.js`, lines 1248-1258 and 1319-1343 **Vulnerability Type**: Unsafe import-time filesystem side effect and insecure sensitive-file creation **Risk Level**: Medium ### Vulnerable Code ```javascript const CONFIG_PATH = path.join(process.env.HOME || process.env.USERPROFILE, '.openclaw', 'openclaw.json'); /** * Loads existing OpenClaw configuration * @returns {Object} The full config */ function loadOpenClawConfig() { try { if (fs.existsSync(CONFIG_PATH)) { return JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf8')); } } catch (err) { // Silent error handling - config will be recreated if needed } return {}; } ``` ```javascript // Save if new config or forceSetup if (isNew || forceSetup) { const dir = path.dirname(CONFIG_PATH); if (!fs.existsSync(dir)) { fs.mkdirSync(dir, { recursive: true }); } fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2)); if (isNew) { console.log('[MQTT] ✓ Auto-Setup: mqtt-client config created in', CONFIG_PATH); } } return config.skills.entries[skillKey]; } // Run auto-setup on import (only once per process) let _autoSetupCalled = false; if (!_autoSetupCalled) { _autoSetupCalled = true; // Run async in background, but don't let errors propagate autoSetupConfig().catch(() => {}); } ``` The generated structure contains a field intended to store a password: ```javascript const template = { enabled: true, env: { MQTT_BROKER: 'localhost', MQTT_BROKER_PORT: '1883', MQTT_USERNAME: '', MQTT_PASSWORD: '', MQTT_CLIENT_ID: '', MQTT_PROTOCOL_VERSION: '4', MQTT_SUBSCRIBE_TOPIC: '#' } }; ``` ### Technical Analysis Importing the library automatically invokes `autoSetupConfig()`, which writes to `~/.openclaw/openclaw.json`. Importing a library is normally expected to initialize code, not modify persistent user configuration. The directory and file are created without explicit ...[truncated 1693 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Remove the automatic `autoSetupConfig()` call from module import. - Require users or deployment tooling to invoke setup explicitly. - Create `~/.openclaw` with mode `0700`. - Create credential-bearing configuration files with mode `0600`. - When updating an existing file, verify and correct its permissions before writing. - Write updates atomically through a securely created temporary file followed by a rename. - Report malformed or unreadable configuration instead of silently treating it as absent. - Avoid storing passwords in plaintext where possible; use environment injection or an operating-system secret store. - If plaintext configuration is unavoidable, clearly document its sensitivity and required ownership and permissions. ]]>
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
  • Memory PoisoningPersistent Context Injection, Context Window Stuffing, Memory Manipulation
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (12)

Ae1

High
Category
analysis-evasion
Content
const { MqttClient } = require('./scripts/mqtt-client.js');
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
const { MqttClient } = require('./scripts/mqtt-client.js');
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Memory Manipulation

High
Category
Memory Poisoning
Content
// Last message
const last = client.getLastMessage('home/sensors/#');

// Clear history
client.clearHistory();
```
Confidence
80% confidence
Finding
Skill manipulates agent memory, state, or stored context. Memory corruption can alter personality, override safety rules, or cause unpredictable behavior.

Vague Triggers

Medium
Confidence
90% confidence
Finding
The documented default subscription topic of `#` subscribes to all topics on the broker, which can expose the client to far more data and trigger activity than intended. In an automation skill, this broad scope increases the chance of unintended message processing, trigger activation, privacy exposure, and operational side effects if the client is connected to a shared or production broker.

Missing User Warnings

Medium
Confidence
83% confidence
Finding
The README documents a broad default subscription topic and states that configuration is auto-written to `~/.openclaw/openclaw.json`, but it does not clearly warn users about the resulting data access and local persistence implications. In this skill context, users may unknowingly grant the client visibility into all broker messages and persist sensitive connection details or behavior-affecting configuration without understanding the security impact.

Lp3

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding
Without declared permissions the skill's intent is opaque and cannot be validated.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The skill defaults `MQTT_SUBSCRIBE_TOPIC` to `#`, which subscribes to all broker topics, but the documentation does not clearly warn that this can expose sensitive messages, device states, credentials accidentally published to MQTT, or cross-tenant/internal automation data. In an MQTT integration skill, this context makes the omission more dangerous because broad topic capture is a primary data-ingestion path and can unintentionally create large-scale privacy and security exposure.

Description-Behavior Mismatch

Medium
Confidence
97% confidence
Finding
This MQTT client module includes side effects unrelated to its core purpose: importing the library can create or modify the user's OpenClaw configuration file. Hidden filesystem mutation during import violates least surprise and can be abused in automation contexts to persist configuration changes or alter later tool behavior without explicit operator consent.

Context-Inappropriate Capability

Medium
Confidence
96% confidence
Finding
Automatically writing ~/.openclaw/openclaw.json from a generic client library is unsafe because consumers may import the module only to access MQTT functionality, not to change host configuration. This creates an unexpected persistence mechanism and can overwrite trust assumptions about local configuration state, especially in shared or agent-managed environments.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
Writing a configuration file into the home directory without prior disclosure or confirmation introduces unauthorized persistent state changes. Even though the written values are template defaults, the act itself can interfere with existing workflows, create misleading trusted configuration, or be leveraged by higher-level automation that assumes user-approved config files.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
Executing auto-setup on import means merely requiring the module can trigger configuration file creation in the user's home directory without a clear warning. In agent or plugin ecosystems, such non-transparent side effects are dangerous because they can change persistent state during analysis, testing, or dependency loading.

Intent-Code Divergence

Low
Confidence
77% confidence
Finding
The documentation says the auto-setup function 'creates or extends' the mqtt-client config and is 'automatically called when importing the module.' In practice, when an entry already exists but is missing fields, the function mutates the in-memory object yet only writes to disk if the config is new or forceSetup is true, so the documented 'extends' behavior does not reliably occur persistently.

Static analysis

No suspicious patterns detected.