Back to skill

Security audit

小米智能家居 (Xiao Mi Home for HA)

Security checks for vulnerabilities and agentic risk

Overview

This Home Assistant skill is coherent for smart-home control, but it asks users to expose a long-lived home-control token in chat and gives broad device-control examples without enough safety scoping.

Install only if you are comfortable giving this skill ongoing Home Assistant control. Do not paste a real HA token into chat; configure it through a local protected mechanism, use a dedicated low-privilege Home Assistant account where possible, prefer HTTPS or a trusted local endpoint, and avoid running the live test or bulk-control examples against critical devices without reviewing the target entities first.

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

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:81
Finding
Home Assistant bearer token may be transmitted over plaintext HTTP or to an untrusted endpoint## Vulnerability Details **File Location**: `SKILL.md:72-82`, `SKILL.md:110-112`, `SKILL.md:225-228`, `test.sh:54-75` **Vulnerability Type**: Plaintext credential transmission and insufficient endpoint validation **Risk Level**: High ### Vulnerable Code `SKILL.md:81-82` configures a plaintext HTTP endpoint: ```bash openclaw config set 'skills."xiaomi-home-ha".env.HA_URL' "http://192.168.31.202:8123" openclaw config set 'skills."xiaomi-home-ha".env.HA_TOKEN' "eyJhbGc..." ``` `SKILL.md:110-112` sends the long-lived token to that configured endpoint: ```bash curl -sf "${HA_URL}/api/" \ -H "Authorization: Bearer ${HA_TOKEN}" ``` `SKILL.md:225-228` similarly sends the token during privileged service calls: ```bash curl -sf -X POST "${HA_URL}/api/services/${DOMAIN}/${SERVICE}" \ -H "Authorization: Bearer ${HA_TOKEN}" \ -H "Content-Type: application/json" \ -d "$(jq -n \ ``` `test.sh:54-75` accepts an unrestricted URL and attaches the bearer token to every helper request: ```bash : "${HA_URL:?'HA_URL is required. Export it before running.'}" : "${HA_TOKEN:?'HA_TOKEN is required. Export it before running.'}" pass "HA_URL set: ${HA_URL}" pass "HA_TOKEN set (${#HA_TOKEN} chars)" ha_get() { curl -sf "${HA_URL}$1" \ -H "Authorization: Bearer ${HA_TOKEN}" \ -H "Content-Type: application/json" } ha_post() { curl -sf -X POST "${HA_URL}$1" \ -H "Authorization: Bearer ${HA_TOKEN}" \ -H "Content-Type: application/json" \ -d "$2" } ha_status() { curl -s -o /dev/null -w "%{http_code}" "${HA_URL}$1" \ -H "Authorization: Bearer ${HA_TOKEN}" } ``` ### Technical Analysis The documented configuration explicitly uses an unencrypted `http://` URL while the requests include a reusable Home Assistant long-lived access token in the `Authorization` header. Plain HTTP does not provide confidentiality or server authentication. A network observer or active m ...[truncated 2056 chars]
Remediation
## Remediation Suggestions 1. Require an `https://` Home Assistant URL for non-loopback connections and reject plaintext HTTP before sending the token. 2. Permit HTTP only for explicit loopback testing, such as `127.0.0.1` or `localhost`, and never as the primary production example. 3. Validate `HA_URL` using a strict URL parser. Allow only expected schemes, ports, and configured hostnames or IP addresses. 4. Preserve TLS certificate verification and do not recommend `curl -k` or `--insecure`. 5. Use a trusted certificate for local Home Assistant deployments, or place Home Assistant behind a properly configured TLS reverse proxy. 6. Use a dedicated Home Assistant account with the minimum practical permissions rather than an administrator's token. 7. Avoid asking users to disclose tokens in chat. Direct them to configure secrets through a protected local interface or environment file with restrictive permissions. 8. Add a preflight check to `test.sh` that terminates before any request if the endpoint is insecure or outside an explicit allowlist. 9. Rotate any token that may already have traversed an untrusted plaintext network.

T08 · Insecure Dependencies

Warning
Location
SKILL.md:58
Finding
Unpinned third-party package is installed globally through npm## Vulnerability Details **File Location**: `SKILL.md:55-58` **Vulnerability Type**: Unpinned global dependency installation **Risk Level**: Medium ### Vulnerable Code ```bash npm i -g node-jq ``` ### Technical Analysis The setup instructions install the mutable latest release of the third-party `node-jq` package globally. No exact version, package integrity value, lockfile, provenance check, or repository verification is specified. npm packages can execute lifecycle scripts during installation. A malicious or compromised package release could consequently execute code with the privileges of the user running the command. Global installation also increases scope by modifying the user's shared Node.js environment rather than an isolated project environment. This is a supply-chain exposure rather than evidence that the named package is currently malicious. ### Attack Path 1. The package publisher account, npm package, or an upstream dependency is compromised, or a future release becomes malicious. 2. A user follows the documented fallback command. 3. npm resolves the unspecified version to the latest available release. 4. npm downloads the package and may execute its installation lifecycle scripts. 5. Malicious code executes under the invoking user's account and can access data and resources available to that account. ### Impact Assessment Successful exploitation could provide arbitrary code execution with the privileges of the user performing the installation. Potential effects include: - Reading user-accessible files and environment variables, including Home Assistant configuration or tokens. - Modifying the global Node.js installation or commands used by other projects. - Installing additional malicious components within user-writable locations. - Making outbound network requests or altering local development files. The package is not installed with `sudo` in the documented command, so root-level compro ...[truncated 115 chars]
Remediation
## Remediation Suggestions 1. Prefer installing the native `jq` binary from a trusted operating-system package repository. 2. If an npm fallback is necessary, pin an explicitly reviewed package version rather than resolving the latest release. 3. Verify package provenance, publisher identity, release history, and integrity before recommending it. 4. Use a lockfile and integrity hashes where npm dependencies are managed as part of the project. 5. Install the dependency locally in an isolated project directory instead of globally. 6. Disable lifecycle scripts with `--ignore-scripts` when the package can function without them. 7. Consider distributing a small, audited alternative based on already required runtime components rather than introducing an additional global dependency. 8. Document the exact trusted version and establish a process for reviewing updates before changing it.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (24)

Credential Access

High
Category
Privilege Escalation
Content
| 变量 | 说明 | 是否必填 |
|------|------|----------|
| `HA_URL` | HA 地址,如 `http://192.168.31.202:8123` | ✅ 必填 |
| `HA_TOKEN` | 长期访问令牌 (Long-Lived Access Token) | ✅ 必填 |
| `HA_DEFAULT_ENTITY` | 未指定实体时的默认值,如 `light.bed_lamp` | 可选 |

### 2. 安装依赖 / Install Dependencies
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
### 3. 获取 Token / How to Get Token

> HA Web → 右下角头像 → **安全** → **长期访问令牌** → **创建令牌** → 复制  
> HA UI → Profile → Security → Long-Lived Access Tokens → Create Token

### 4. 写入配置(三种方式)/ Configure (3 ways)
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Ssd 3

High
Confidence
99% confidence
Finding
The documentation creates a natural-language workflow where a user reveals a valid HA token directly to the model so it can configure the skill automatically. This is dangerous because the token is a reusable secret with persistent API access, and disclosure to the model/chat system can lead to unauthorized reuse or later compromise.

Missing User Warnings

High
Confidence
99% confidence
Finding
The skill explicitly tells users to paste a live Home Assistant long-lived access token into an AI/chat conversation for configuration. That creates a direct credential disclosure path into conversation history, logs, and any downstream model/tool telemetry, exposing a token that grants broad control over the user's home automation environment.

Credential Access

High
Category
Privilege Escalation
Content
#
# Environment:
#   HA_URL            Required. HA base URL.
#   HA_TOKEN          Required. Long-lived access token.
#   HA_TEST_ENTITY    Optional. Entity for write tests (default: auto-detect first light)
#   HA_SKIP_WRITE     Set to 1 to skip write (control) tests (read-only mode)
#
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Missing User Warnings

Medium
Confidence
84% confidence
Finding
The skill advertises arbitrary Home Assistant service calls and broad device control without warning users that actions may affect locks, climate, power, alarms, or other home systems. In this context, omission of safety guidance increases the chance of accidental disruptive actions, especially because the skill is designed for natural-language execution across many device types.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
```bash
# Ubuntu / Debian
sudo apt-get install -y jq

# macOS
brew install jq
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
```bash
# Ubuntu / Debian
sudo apt-get install -y jq

# macOS
brew install jq
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Session Persistence

Medium
Category
Rogue Agent
Content
### 3. 获取 Token / How to Get Token

> HA Web → 右下角头像 → **安全** → **长期访问令牌** → **创建令牌** → 复制  
> HA UI → Profile → Security → Long-Lived Access Tokens → Create Token

### 4. 写入配置(三种方式)/ Configure (3 ways)
Confidence
91% confidence
Finding
This duplicate finding reflects the same underlying issue: a reusable long-lived token is configured in a persistent way and may survive into subsequent sessions. In context, persistence materially increases risk because anyone obtaining the stored token can continue controlling the user's Home Assistant environment until the token is revoked.

Session Persistence

Medium
Category
Rogue Agent
Content
### 3. 获取 Token / How to Get Token

> HA Web → 右下角头像 → **安全** → **长期访问令牌** → **创建令牌** → 复制  
> HA UI → Profile → Security → Long-Lived Access Tokens → Create Token

### 4. 写入配置(三种方式)/ Configure (3 ways)
Confidence
91% confidence
Finding
This duplicate finding reflects the same underlying issue: a reusable long-lived token is configured in a persistent way and may survive into subsequent sessions. In context, persistence materially increases risk because anyone obtaining the stored token can continue controlling the user's Home Assistant environment until the token is revoked.

External Transmission

Medium
Category
Data Exfiltration
Content
SERVICE="turn_on"                   # HA 服务名 / HA service name
SERVICE_DATA='{"transition": 0.5}'  # 附加参数(可为空对象)/ extra params (can be {})

curl -sf -X POST "${HA_URL}/api/services/${DOMAIN}/${SERVICE}" \
  -H "Authorization: Bearer ${HA_TOKEN}" \
  -H "Content-Type: application/json" \
  -d "$(jq -n \
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
```bash
# 所有灯调至 10% 暖黄 / All lights dim warm
for entity in light.bedroom light.corridor; do
  curl -sf -X POST "${HA_URL}/api/services/light/turn_on" \
    -H "Authorization: Bearer ${HA_TOKEN}" \
    -H "Content-Type: application/json" \
    -d "{\"entity_id\": \"${entity}\", \"brightness_pct\": 10, \"color_temp_kelvin\": 2700}" &
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
-H "Authorization: Bearer ${HA_TOKEN}" \
    | jq -r --arg d "${domain}." '[.[] | select(.entity_id | startswith($d)) | .entity_id] | .[]' \
    | while read -r eid; do
        curl -sf -X POST "${HA_URL}/api/services/${domain}/turn_off" \
          -H "Authorization: Bearer ${HA_TOKEN}" \
          -H "Content-Type: application/json" \
          -d "{\"entity_id\": \"${eid}\"}" > /dev/null
Confidence
82% confidence
Finding
While the network call itself is expected, this example performs bulk shutdown across all lights and switches with no confirmation or scoping safeguards. In a home automation context, broad natural-language-triggered mass actions can create safety and availability issues, especially if switches control critical appliances or infrastructure.

External Transmission

Medium
Category
Data Exfiltration
Content
# ── HTTP helpers ──────────────────────────────────────────────────────────────
ha_get() {
  curl -sf "${MOCK_URL}$1" -H "Authorization: Bearer ${MOCK_TOKEN}"
}
ha_post() {
  curl -sf -X POST "${MOCK_URL}$1" \
Confidence
70% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
STATE=$(jq_val "$(ha_get '/api/states/media_player.xiaomi_speaker')" "d.state")
[[ "$STATE" == "paused" ]] && pass "T6.6 media_pause → paused" || fail "T6.6 — expected paused, got ${STATE}"

SCENE_ST=$(curl -s -o /dev/null -w "%{http_code}" \
  -X POST "${MOCK_URL}/api/services/scene/turn_on" \
  -H "Authorization: Bearer ${MOCK_TOKEN}" \
  -H "Content-Type: application/json" \
Confidence
70% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
# ── Group 7: Error Handling ────────────────────────────────────────────────────
section "Group 7: Error Handling"

STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
  -X POST "${MOCK_URL}/api/services/light/turn_on" \
  -H "Authorization: Bearer ${MOCK_TOKEN}" \
  -H "Content-Type: application/json" \
Confidence
70% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
# ── Group 7: Error Handling ────────────────────────────────────────────────────
section "Group 7: Error Handling"

STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
  -X POST "${MOCK_URL}/api/services/light/turn_on" \
  -H "Authorization: Bearer ${MOCK_TOKEN}" \
  -H "Content-Type: application/json" \
Confidence
70% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
STATUS=$(ha_status "/api/states/switch.nonexistent_zzz")
[[ "$STATUS" == "404" ]] && pass "T7.2 GET unknown entity → HTTP 404" || fail "T7.2 — expected 404, got ${STATUS}"

STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
  -X POST "${MOCK_URL}/api/services/light/turn_on" \
  -H "Content-Type: application/json" \
  -d '{"entity_id":"light.bed_lamp"}')
Confidence
70% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
ENTITY_ID_V="light.ceiling"
SERVICE_DATA='{"brightness_pct":80,"transition":0.5}'
MERGED=$(node -e "const e='${ENTITY_ID_V}'; const x=${SERVICE_DATA}; console.log(JSON.stringify({entity_id:e,...x}));")
RESP_ST=$(curl -s -o /dev/null -w "%{http_code}" \
  -X POST "${MOCK_URL}/api/services/light/turn_on" \
  -H "Authorization: Bearer ${MOCK_TOKEN}" \
  -H "Content-Type: application/json" \
Confidence
70% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
# ── Preflight ────────────────────────────────────────────────────────────────
section "Preflight: Environment & Dependencies"

for bin in curl node; do
  if command -v "$bin" &>/dev/null; then
    pass "binary available: $bin"
  else
Confidence
88% confidence
Finding
The script transmits a long-lived Home Assistant bearer token to an external service endpoint defined by HA_URL via curl. In the intended test context this network transmission is necessary, but it is still security-relevant because a misconfigured, attacker-controlled, or non-TLS HA_URL could cause credential disclosure and remote access to the user's Home Assistant instance.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The script performs live state-changing operations against a real Home Assistant instance, including turn_on, brightness changes, toggle, and turn_off, with only an environment variable to skip writes. Because it auto-selects a device if HA_TEST_ENTITY is unset and does not present an explicit safety warning or confirmation step, running it can unintentionally actuate real devices and disrupt the environment.

Intent-Code Divergence

Medium
Confidence
89% confidence
Finding
The file header documents this script as an 'Integration Test Suite (Live HA)' for exercising a Home Assistant instance, but Group 8 enforces that a local SKILL.md contains a specific skill name ('xiaomi-home-ha'), Chinese content, and template markers. That is not merely additional coverage; it contradicts the apparent intent of this file as a generic HA live test by embedding repository/content assertions about a particular skill package.

Natural-Language Policy Violations

Low
Confidence
86% confidence
Finding
These lines explicitly test SKILL.md for both Chinese terms and English terms, and label bilingual content as something to verify/present. That natural-language requirement imposes a locale expectation without any user opt-in or documented regional justification in this file.

Natural-Language Policy Violations

Low
Confidence
95% confidence
Finding
The test requires Chinese content to be present in SKILL.md by failing when specific Chinese terms are missing. This imposes a language requirement without offering user choice or documenting a justified locale-specific constraint in this file.

Static analysis

No suspicious patterns detected.