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

Content
View full analysis

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
View 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

Content
View full analysis

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
View 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
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · SKILL.md (reported line 43)May include surrounding context.

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

### 2. 安装依赖 / Install Dependencies

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · SKILL.md (reported line 66)May include surrounding context.

md
### 3. 获取 Token / How to Get Token

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

### 4. 写入配置(三种方式)/ Configure (3 ways)

Ssd 3

High
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · test.sh (reported line 12)May include surrounding context.

sh
#
# 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)
#

Missing User Warnings

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

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.md (reported line 52)May include surrounding context.

bash
# Ubuntu / Debian
sudo apt-get install -y jq

# macOS
brew install jq

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.md (reported line 57)May include surrounding context.

bash
# Ubuntu / Debian
sudo apt-get install -y jq

# macOS
brew install jq

Session Persistence

Medium
Category
Rogue Agent
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.

Content

Scanner excerpt · SKILL.md (reported line 66)May include surrounding context.

md
### 3. 获取 Token / How to Get Token

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

### 4. 写入配置(三种方式)/ Configure (3 ways)

Session Persistence

Medium
Category
Rogue Agent
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.

Content

Scanner excerpt · SKILL.md (reported line 66)May include surrounding context.

md
### 3. 获取 Token / How to Get Token

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

### 4. 写入配置(三种方式)/ Configure (3 ways)

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 225)May include surrounding context.

md
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 \

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 341)May include surrounding context.

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}" &

External Transmission

Medium
Category
Data Exfiltration
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.

Content

Scanner excerpt · SKILL.md (reported line 375)May include surrounding context.

md
-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

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · test-mock.sh (reported line 55)May include surrounding context.

sh
# ── HTTP helpers ──────────────────────────────────────────────────────────────
ha_get() {
  curl -sf "${MOCK_URL}$1" -H "Authorization: Bearer ${MOCK_TOKEN}"
}
ha_post() {
  curl -sf -X POST "${MOCK_URL}$1" \

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · test-mock.sh (reported line 215)May include surrounding context.

sh
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" \

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · test-mock.sh (reported line 225)May include surrounding context.

sh
# ── 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" \

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · test-mock.sh (reported line 241)May include surrounding context.

sh
# ── 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" \

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · test-mock.sh (reported line 235)May include surrounding context.

sh
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"}')

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · test-mock.sh (reported line 260)May include surrounding context.

sh
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" \

External Transmission

Medium
Category
Data Exfiltration
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.

Content

Scanner excerpt · test.sh (reported line 47)May include surrounding context.

sh
# ── Preflight ────────────────────────────────────────────────────────────────
section "Preflight: Environment & Dependencies"

for bin in curl node; do
  if command -v "$bin" &>/dev/null; then
    pass "binary available: $bin"
  else

Missing User Warnings

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.