Back to skill

Security audit

Tapo

Security checks for vulnerabilities and agentic risk

Overview

This Tapo skill is coherent, but it uses sensitive smart-home and camera control paths with plaintext HTTP tokens, mutable dependencies, and host-network deployment examples.

Review before installing. Prefer pinned mcporter and inspector versions, pin the Tapo MCP container by digest, avoid plaintext HTTP for non-loopback access by using HTTPS/VPN/tunneling, keep tokens out of shell history, and only use host networking on an isolated trusted network segment.

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)

T08 · Insecure Dependencies

Warning
Location
SKILL.md:17
Finding
Unpinned npm Packages Are Downloaded and Executed Through npx<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:17-101`, `references/setup.md:17-83`, and `references/tapo-mcp-setup.md:156-161` **Vulnerability Type**: Unpinned executable third-party dependencies **Risk Level**: Medium ### Vulnerable Code ```bash npx mcporter config add tapo http://<TAPO_MCP_IP> \ --transport http \ --header "Authorization=Bearer <YOUR_TOKEN>" \ --scope home npx mcporter list tapo --schema npx mcporter call tapo.list_devices ``` The MCP Inspector is also invoked without a version constraint: ```bash npx @modelcontextprotocol/inspector http://127.0.0.1:3000 npx @modelcontextprotocol/inspector \ --header "Authorization: Bearer $TAPO_MCP_API_KEY" \ http://127.0.0.1:3000 ``` ### Technical Analysis The documentation repeatedly instructs users to invoke `mcporter` and `@modelcontextprotocol/inspector` through `npx` without specifying reviewed versions. When the requested package is not already installed locally, `npx` can resolve it from the npm registry, download it, and execute its package code immediately. Because no exact version, lockfile, or integrity hash is specified, the effective code executed by these commands can change after this Skill has been audited. This creates a supply-chain trust boundary between the Skill and mutable registry content. A compromised maintainer account, malicious package release, or upstream package takeover could result in arbitrary code running under the invoking user's account. ### Attack Path 1. An attacker compromises an upstream npm package, its publisher account, or the package distribution process. 2. The attacker publishes a modified version of `mcporter` or `@modelcontextprotocol/inspector`. 3. A user follows the documented command without an explicit version. 4. `npx` resolves and downloads the modified package. 5. Package installation or runtime code executes with the user's privileges. 6. The malicious package can access files available to that user, including MCP ...[truncated 722 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin every executable npm dependency to an exact reviewed version, for example: ```bash npx --yes mcporter@<REVIEWED_EXACT_VERSION> list tapo --schema npx --yes @modelcontextprotocol/inspector@<REVIEWED_EXACT_VERSION> \ http://127.0.0.1:3000 ``` 2. Prefer declaring dependencies in a package manifest and committing a lockfile rather than downloading packages during each invocation. 3. Use `npm ci` in a controlled installation step so dependency resolution follows the lockfile. 4. Validate registry provenance and package integrity. Where supported, verify signatures or attestations. 5. Disable automatic package installation during normal Skill operation and invoke only a previously installed, reviewed local binary. 6. Periodically update the pinned versions through an explicit review and testing process. ]]>

T08 · Insecure Dependencies

Error
Location
references/tapo-mcp-setup.md:62
Finding
Mutable Container Image Is Deployed with Host Network Access<![CDATA[ ## Vulnerability Details **File Location**: `references/tapo-mcp-setup.md:62-75` and `references/tapo-mcp-setup.md:112-115` **Vulnerability Type**: Mutable container dependency combined with reduced network isolation **Risk Level**: High ### Vulnerable Code Docker deployment: ```bash docker run --rm \ --network host \ -e TAPO_MCP_USERNAME="you@example.com" \ -e TAPO_MCP_PASSWORD="<YOUR_TAPO_PASSWORD>" \ -e TAPO_MCP_CAMERA_USERNAME="<YOUR_CAMERA_ACCOUNT_USERNAME>" \ -e TAPO_MCP_CAMERA_PASSWORD="<YOUR_CAMERA_ACCOUNT_PASSWORD>" \ -e TAPO_MCP_DISCOVERY_TARGET="192.168.1.255" \ -e TAPO_MCP_API_KEY="<YOUR_TAPO_MCP_API_KEY>" \ ghcr.io/mihai-dinculescu/tapo-mcp:latest ``` Kubernetes deployment: ```yaml spec: hostNetwork: true containers: - name: tapo-mcp image: ghcr.io/mihai-dinculescu/tapo-mcp:latest ``` ### Technical Analysis The deployment uses the mutable `latest` container tag rather than an immutable image digest. Consequently, the exact image executed can change whenever the remote tag is updated, even though the deployment command itself remains unchanged. At the same time, the image receives host-network access through Docker's `--network host` or Kubernetes' `hostNetwork: true`. Host networking may be operationally useful for UDP broadcast discovery, but it removes normal container network namespace isolation and gives the container direct access to host and LAN network interfaces. The combination is particularly risky: remotely mutable code is granted broad network reach and receives Tapo account, camera account, and MCP API credentials as environment variables. ### Attack Path 1. An attacker compromises the image registry, image publisher account, build pipeline, or upstream project. 2. The attacker replaces or updates `ghcr.io/mihai-dinculescu/tapo-mcp:latest` with a hostile image. 3. A user pulls or redeploys the documented `latest` tag. 4. Docker or Kubernetes starts the hostile image with host networking ...[truncated 998 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin the image to an immutable, reviewed digest: ```bash ghcr.io/mihai-dinculescu/tapo-mcp@sha256:<VERIFIED_DIGEST> ``` 2. Verify image signatures and build provenance before deployment. 3. Avoid host networking where deployment architecture permits it. 4. If UDP discovery requires host networking: - Run the service on a dedicated host, node, or isolated VLAN. - Apply host firewall and egress restrictions. - Restrict communication to required Tapo device subnets and trusted management endpoints. - Prevent access to cloud metadata services and unrelated internal networks. 5. Apply a restrictive container security context: - Run as a non-root user. - Drop all unnecessary Linux capabilities. - Use a read-only root filesystem. - Enable seccomp and mandatory access-control profiles. - Prevent privilege escalation. 6. Inject secrets through a dedicated secret-management mechanism rather than ordinary command-line environment assignments. 7. Establish an explicit process for reviewing and updating the pinned digest. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:21
Finding
Reusable Bearer Token Is Transmitted over Plaintext HTTP<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:21-30`, `references/setup.md:8-20`, and `references/tapo-mcp-setup.md:43-59` **Vulnerability Type**: Plaintext transmission of authentication credentials **Risk Level**: High ### Vulnerable Code ```bash npx mcporter config add tapo http://<TAPO_MCP_IP> \ --transport http \ --header "Authorization=Bearer <YOUR_TOKEN>" \ --scope home ``` The setup guide explicitly describes the server as an HTTP endpoint on the LAN: ```text - A running Tapo MCP server on your network (HTTP transport) - The server URL (e.g. `http://192.168.1.100`) - A Bearer auth token ``` ### Technical Analysis The documented configuration sends an `Authorization: Bearer` credential to an `http://` endpoint. HTTP does not provide transport encryption, server authentication, or message integrity. Bearer tokens are possession-based credentials: any party that obtains the token can generally use it until it expires or is revoked. Host-header allowlisting and application-level token checks do not protect the token while it traverses the network. An attacker able to observe LAN traffic, control a network intermediary, operate a malicious access point, or redirect traffic may capture the token or tamper with MCP responses. The documentation does not establish TLS certificate validation or another encrypted tunnel. ### Attack Path 1. A user configures `mcporter` with a LAN endpoint such as `http://192.168.1.100`. 2. `mcporter` sends the reusable bearer token in the HTTP `Authorization` header. 3. An attacker in a network-observation or intermediary position captures the plaintext request. 4. The attacker extracts the bearer token. 5. The attacker connects to the Tapo MCP endpoint using the stolen token. 6. Subject to network reachability and server-side capabilities, the attacker invokes tools for device enumeration, state access, device control, or camera snapshots. A traffic-redirection attacker could also impersonate the ...[truncated 821 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Require HTTPS for every non-loopback MCP connection. 2. Configure the client to validate a certificate issued for the exact server hostname. 3. Do not recommend disabling certificate verification. 4. For private deployments, use one of: - A certificate from a trusted private certificate authority. - A reverse proxy that terminates TLS securely. - A mutually authenticated TLS configuration. - An authenticated VPN or encrypted SSH tunnel with the MCP server bound to loopback. 5. Continue to use bearer authentication in addition to transport encryption; TLS does not replace application authorization. 6. Use high-entropy, limited-scope tokens and support expiration and rotation. 7. Revoke and replace tokens previously transmitted over an untrusted plaintext network. 8. Update examples to use a hostname-based HTTPS URL, such as: ```bash npx mcporter config add tapo https://tapo-mcp.example.lan \ --transport http \ --header "Authorization=Bearer <YOUR_TOKEN>" \ --scope home ``` ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
references/tapo-mcp-setup.md:62
Finding
Account Passwords and API Keys Are Supplied as Command-Line Arguments<![CDATA[ ## Vulnerability Details **File Location**: `references/tapo-mcp-setup.md:62-70` and `references/tapo-mcp-setup.md:81-87` **Vulnerability Type**: Credential exposure through shell history, process arguments, and logs **Risk Level**: Medium ### Vulnerable Code Docker example: ```bash docker run --rm \ --network host \ -e TAPO_MCP_USERNAME="you@example.com" \ -e TAPO_MCP_PASSWORD="<YOUR_TAPO_PASSWORD>" \ -e TAPO_MCP_CAMERA_USERNAME="<YOUR_CAMERA_ACCOUNT_USERNAME>" \ -e TAPO_MCP_CAMERA_PASSWORD="<YOUR_CAMERA_ACCOUNT_PASSWORD>" \ -e TAPO_MCP_DISCOVERY_TARGET="192.168.1.255" \ -e TAPO_MCP_API_KEY="<YOUR_TAPO_MCP_API_KEY>" \ ghcr.io/mihai-dinculescu/tapo-mcp:latest ``` Kubernetes Secret creation example: ```bash kubectl create secret generic tapo-mcp-secrets \ --from-literal=TAPO_MCP_USERNAME="you@example.com" \ --from-literal=TAPO_MCP_PASSWORD="<YOUR_TAPO_PASSWORD>" \ --from-literal=TAPO_MCP_CAMERA_USERNAME="<YOUR_CAMERA_ACCOUNT_USERNAME>" \ --from-literal=TAPO_MCP_CAMERA_PASSWORD="<YOUR_CAMERA_ACCOUNT_PASSWORD>" \ --from-literal=TAPO_MCP_API_KEY="<YOUR_TAPO_MCP_API_KEY>" ``` ### Technical Analysis The examples instruct users to insert sensitive credentials directly into shell command arguments. Commands entered interactively are commonly retained in shell history. They may also be captured by terminal recording, support transcripts, audit tooling, CI logs, orchestration wrappers, or command telemetry. Depending on the operating system and process timing, command-line arguments may also be observable through process-inspection interfaces by other local principals. Although Docker's `-e NAME=value` ultimately places values in the container environment, the immediate concern here is that the values first appear in the invoking command line. Creating a Kubernetes Secret protects the resulting object only according to cluster secret controls; it does not remove copies already recorded in the local shell history or external log ...[truncated 1213 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not place secret values directly in documented command lines. 2. For Docker: - Use a protected environment file with restrictive permissions. - Prefer Docker secrets or an external secret manager where available. - Ensure the file is excluded from source control. Example: ```bash chmod 600 /secure/path/tapo-mcp.env docker run --rm \ --network host \ --env-file /secure/path/tapo-mcp.env \ ghcr.io/mihai-dinculescu/tapo-mcp@sha256:<VERIFIED_DIGEST> ``` 3. For Kubernetes: - Use `--from-file` with protected temporary files rather than `--from-literal`. - Prefer External Secrets, Sealed Secrets, or a cloud/platform secret manager. - Enable Kubernetes Secret encryption at rest and strict RBAC. 4. Prevent secret values from appearing in CI logs and shell tracing output. 5. Treat disabling shell history as a secondary defense, not the primary secret-delivery mechanism. 6. Rotate credentials that have already been entered directly into commands or exposed in logs. 7. Use distinct, minimally privileged credentials for the MCP service and camera access. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • 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
Findings (38)

Privileged Container / Container Escape

High
Category
Privilege Escalation
Content
```bash
docker run --rm \
  --network host \
  -e TAPO_MCP_USERNAME="you@example.com" \
  -e TAPO_MCP_PASSWORD="<YOUR_TAPO_PASSWORD>" \
  -e TAPO_MCP_CAMERA_USERNAME="<YOUR_CAMERA_ACCOUNT_USERNAME>" \
Confidence
80% confidence
Finding
Potential security issue detected. Manual review is recommended.

Privileged Container / Container Escape

High
Category
Privilege Escalation
Content
```bash
docker run --rm \
  --network host \
  -e TAPO_MCP_USERNAME="you@example.com" \
  -e TAPO_MCP_PASSWORD="<YOUR_TAPO_PASSWORD>" \
  -e TAPO_MCP_CAMERA_USERNAME="<YOUR_CAMERA_ACCOUNT_USERNAME>" \
Confidence
80% confidence
Finding
Potential security issue detected. Manual review is recommended.

Privileged Container / Container Escape

High
Category
Privilege Escalation
Content
> **Note:** The image binds to `0.0.0.0:3000`, so `TAPO_MCP_API_KEY` is required — the server refuses to start on a non-loopback address without it (see Network exposure above). To reach the server by hostname or LAN IP rather than loopback, also set `TAPO_MCP_ALLOWED_HOSTS`.

> **Note:** `--network host` is required so the container can reach Tapo devices on your local network via UDP broadcast for discovery. On macOS and Windows, `--network host` is not supported — you can use `-p 3000:3000` instead, but device discovery won't work as Docker Desktop runs containers inside a VM without LAN access.

### Kubernetes
Confidence
80% confidence
Finding
Potential security issue detected. Manual review is recommended.

Privileged Kubernetes Workload

High
Category
Tool Misuse
Content
labels:
        app: tapo-mcp
    spec:
      hostNetwork: true
      containers:
        - name: tapo-mcp
          image: ghcr.io/mihai-dinculescu/tapo-mcp:latest
Confidence
87% confidence
Finding
`hostNetwork: true` removes Kubernetes pod network isolation and exposes the workload directly on the node network namespace. In a smart-home control service that can discover and control LAN devices, this increases lateral movement and blast radius if the service or image is compromised, especially because it is intended to access sensitive internal devices.

Privileged Kubernetes Workload

High
Category
Tool Misuse
Content
key: TAPO_MCP_DISCOVERY_TARGET
```

> **Note:** `hostNetwork: true` is required for UDP broadcast discovery, similar to `--network host` in Docker. Because clients reach the server by node IP or hostname rather than loopback, set `TAPO_MCP_ALLOWED_HOSTS` accordingly (see Network exposure above).

## Testing
Confidence
60% confidence
Finding
Code deploys a privileged Kubernetes workload (privileged container, hostPath mount, or host namespaces). This grants root on the node and is a node/cluster takeover vector.

Rp1

Medium
Category
MCP Rug Pull
Confidence
94% confidence
Finding
The skill repeatedly instructs users to invoke `npx mcporter` without pinning an exact package version. Because `npx` may fetch and execute the latest published package, a compromised upstream release, typo-squatted dependency, or unexpected breaking update could result in arbitrary code execution on the user's machine or unsafe interaction with the home automation environment.

Rp1

Medium
Category
MCP Rug Pull
Confidence
94% confidence
Finding
This command uses `npx mcporter` without an explicit version, which means execution behavior depends on whatever package version is current at runtime. In a skill that configures access to smart-home devices and bearer tokens, unpinned execution increases supply-chain risk and could expose credentials or permit unauthorized device control if the fetched package is malicious.

Rp1

Medium
Category
MCP Rug Pull
Confidence
94% confidence
Finding
An unpinned `npx mcporter` invocation can silently pull a newer or malicious package version at execution time. Since this skill is used to discover devices and operate cameras, lights, and sensors on a home network, the trust boundary is significant and a package compromise could lead to local-network reconnaissance or unauthorized actions.

Rp1

Medium
Category
MCP Rug Pull
Confidence
94% confidence
Finding
The example at this line depends on an unpinned package fetched through `npx`, creating a supply-chain execution risk. In this context, a malicious or altered package could manipulate device checks, capture configuration data, or execute arbitrary code while appearing to be a routine device validation command.

Rp1

Medium
Category
MCP Rug Pull
Confidence
94% confidence
Finding
This unversioned `npx mcporter` command exposes users to remote package substitution or unexpected updates. Because the command interacts with home-device state and potentially sensitive metadata like internal IP addresses and device identifiers, exploitation could facilitate broader compromise of the user's smart-home environment.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
### get_device_state

Get a device's current state. Automatically runs `check_device` first.

```bash
# Device info
Confidence
80% 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.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
### get_device_state

Get a device's current state. Automatically runs `check_device` first.

```bash
# Device info
Confidence
80% 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.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
### get_device_state

Get a device's current state. Automatically runs `check_device` first.

```bash
# Device info
Confidence
80% 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.

Rp1

Medium
Category
MCP Rug Pull
Confidence
94% confidence
Finding
Running `npx mcporter` without a fixed version allows whatever package resolves at runtime to execute with the user's privileges. In a skill that accesses trigger logs and sensor history, a compromised package could exfiltrate behavioral data or pivot into further commands against the local smart-home infrastructure.

Rp1

Medium
Category
MCP Rug Pull
Confidence
94% confidence
Finding
The command on this line is another instance of unpinned `npx` execution, which creates unnecessary exposure to malicious or unreviewed package updates. Given that it retrieves sensor records from home devices, compromise could leak sensitive occupancy or environmental data and undermine user privacy.

Rp1

Medium
Category
MCP Rug Pull
Confidence
94% confidence
Finding
This unpinned invocation may execute arbitrary package code from the registry rather than a reviewed, stable client version. Because the skill is intended for controlling devices on a trusted local network, the impact of a malicious client extends beyond the CLI itself to unauthorized state changes in the user's physical environment.

Rp1

Medium
Category
MCP Rug Pull
Confidence
94% confidence
Finding
This command controls device power state using an unpinned `npx` package, introducing a direct path from package compromise to physical device manipulation. In smart-home contexts, unauthorized switching of plugs, lights, or other actuators can have safety, privacy, and operational consequences beyond typical software-only impact.

Rp1

Medium
Category
MCP Rug Pull
Confidence
94% confidence
Finding
Because `npx mcporter` is not version-pinned here, users may unknowingly run a changed or malicious package when issuing device-control actions. The context increases danger because the command affects real smart-home hardware, so exploitation could produce immediate unauthorized changes in the environment.

Rp1

Medium
Category
MCP Rug Pull
Confidence
94% confidence
Finding
The example at this line uses unpinned package execution to change brightness settings on a device. While the action seems simple, the actual risk lies in executing untrusted or unexpectedly updated code in a context with access to device identifiers, internal IPs, and authenticated control over home hardware.

Rp1

Medium
Category
MCP Rug Pull
Confidence
94% confidence
Finding
This unpinned `npx mcporter` call can be substituted by a malicious or incompatible package version at runtime. Since it changes color-capable lights and uses authenticated infrastructure on the home network, abuse could lead to unauthorized control and possible collection of environment-specific data from the interaction flow.

Rp1

Medium
Category
MCP Rug Pull
Confidence
94% confidence
Finding
The multi-capability control example still relies on unpinned package execution, preserving the same supply-chain risk while broadening operational effect. A compromised CLI could batch unauthorized device changes, harvest tokens, or alter requests sent to the Tapo MCP server under the guise of legitimate automation.

Rp1

Medium
Category
MCP Rug Pull
Confidence
95% confidence
Finding
This snapshot command uses unpinned `npx mcporter` in a particularly sensitive context involving camera access and server-side camera credentials. A malicious or altered package could facilitate image capture abuse, credential theft, or exfiltration of private household imagery and metadata.

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.

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.

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.

Static analysis

No suspicious patterns detected.