Back to skill

Security audit

Tasmota

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its smart-device management purpose, but it has under-disclosed broad device-control authority and one script can execute a controller from outside the reviewed package.

Review before installing. This skill can scan your local network, read device and network details, and change smart-home device states. Use it only on networks and Tasmota devices you administer, avoid raw commands unless you understand their effect, and fix or verify the hard-coded external controller path before running bulk status checks.

Vulnerability Patterns
  • Tool Hijacking and SpoofingModifies or replaces tools so legitimate-looking calls execute attacker logic
  • 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)

T07 · Tool Hijacking and Spoofing

Error
Location
scripts/tasmota-status.py:10
Finding

Execution of an Untrusted Controller Script Outside the Audited Package

Content
View full analysis

Vulnerability Details

File Location: scripts/tasmota-status.py, lines 10 and 16-20
Vulnerability Type: Local tool hijacking through a hard-coded external script path
Risk Level: High

Vulnerable Code

python
CSV_FILE = Path.home() / ".openclaw/workspace/memory/tasmota-inventory.csv"

def get_device_status(ip):
    """Get power status from device"""
    try:
        result = subprocess.run(
            ["python3", Path.home() / ".openclaw/workspace/scripts/tasmota-control.py", ip, "status", "0"],
            capture_output=True,
            timeout=3
        )

Technical Analysis

The bulk-status script does not execute the audited controller bundled alongside it at scripts/tasmota-control.py. Instead, it invokes a Python file from the separate, hard-coded path ~/.openclaw/workspace/scripts/tasmota-control.py.

The command uses an argument list rather than a shell, so this is not shell-command injection. The vulnerability is that the identity and integrity of the executed controller are not established. Any process or user capable of creating or modifying the external workspace file can replace the expected controller with arbitrary Python code. The substituted code will execute with the privileges of the user running tasmota-status.py.

This behavior is unnecessary for the declared bulk-status functionality because the audited package already contains the required controller script.

Attack Path

  1. An attacker gains write access to ~/.openclaw/workspace/scripts/, or compromises another process that can write there.
  2. The attacker creates or replaces tasmota-control.py at that location with malicious Python code.
  3. A user runs the documented command:
    bash
    python3 scripts/tasmota-status.py
    
  4. For each inventory entry, subprocess.run() launches the attacker-controlled external script through python3.
  5. The malicious script executes with the ...[truncated 850 chars]
Remediation
View remediation

Remediation Suggestions

Resolve the bundled controller relative to the current script rather than through the user's workspace:

python
SCRIPT_DIR = Path(__file__).resolve().parent
CONTROLLER = SCRIPT_DIR / "tasmota-control.py"

result = subprocess.run(
    ["python3", str(CONTROLLER), ip, "status", "0"],
    capture_output=True,
    timeout=3,
    check=False,
)

Additional hardening measures:

  1. Verify that CONTROLLER is a regular file inside the expected package directory.
  2. Reject symlinks if the deployment model does not require them.
  3. Install package code in a location that is not writable by less-trusted users or processes.
  4. Prefer importing a shared controller module and calling its function directly, avoiding subprocess-based tool resolution entirely.
  5. Make the inventory path explicitly configurable and document its trust boundary.
  6. Validate inventory addresses with Python's ipaddress module rather than accepting every string beginning with 192.
  7. Apply restrictive permissions to inventory and package files.
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (11)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The documented purpose is narrower than the reported code behavior, especially if the implementation allows arbitrary raw Tasmota commands beyond the listed power/brightness/color/status operations. That mismatch can hide broader device-control capability from users and reviewers, enabling unexpected changes to device configuration or behavior on the local network.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The documented purpose is narrower than the reported code behavior, especially if the implementation allows arbitrary raw Tasmota commands beyond the listed power/brightness/color/status operations. That mismatch can hide broader device-control capability from users and reviewers, enabling unexpected changes to device configuration or behavior on the local network.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill documents use of shell and network-capable scripts but do not declare any explicit tool scope or permissions boundary. That makes it easier for an agent to invoke network scanning and device-control behavior without clear policy gating, increasing the chance of unintended host probing or device manipulation.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The invocation description is broad enough to trigger the skill for many generic Tasmota-related requests, including ones where network scanning or real device control may not be appropriate. Over-broad routing increases the likelihood of unnecessary execution of sensitive actions on a local network.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The discovery section instructs users to run a subnet scan but does not clearly warn that this will actively probe hosts on the local network. Absent that warning, an agent or user may initiate scanning in environments where such probing is unauthorized, disruptive, or policy-violating.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The control section shows commands that can immediately change physical device state, including powering devices on or off, without an explicit safety warning. In a smart-home or operational setting, unexpected state changes can interrupt service, affect safety-related equipment, or violate user intent.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The status function exposes multiple Tasmota status classes, including network, firmware, parameters, logs, MQTT, and time data, which can reveal internal device and network details. In a smart-home management skill this is somewhat expected functionality, but exposing these details without access controls, minimization, or clear warning can leak useful reconnaissance information about the local environment.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The raw passthrough path sends arbitrary commands directly to the device with no validation, restriction, or warning, allowing users or upstream callers to invoke potentially dangerous Tasmota functionality. Because the skill is intended for device discovery and control on local networks, this broad command surface increases the risk of unauthorized reconfiguration, information disclosure, or service disruption of smart-home devices.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script explicitly falls back to passing any user-supplied arguments directly to the Tasmota command API, which expands the capability far beyond the documented power, status, brightness, and color operations. In the context of a local-device control skill, this enables execution of sensitive Tasmota commands such as configuration changes, restarts, firmware-related actions, or other administrative operations without restriction or warning.

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 · scripts/tasmota-discovery.py (reported line 105)May include surrounding context.

python
def ping_scan(ip):
    """Quick ping check to see if host is up"""
    try:
        result = subprocess.run(
            ['ping', '-c', '1', '-W', '1', ip],
            capture_output=True,
            timeout=2

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 · scripts/tasmota-status.py (reported line 16)May include surrounding context.

python
def get_device_status(ip):
    """Get power status from device"""
    try:
        result = subprocess.run(
            ["python3", Path.home() / ".openclaw/workspace/scripts/tasmota-control.py", ip, "status", "0"],
            capture_output=True,
            timeout=3

Static analysis

No suspicious patterns detected.