Back to skill

Security audit

Mijia Control

Security checks for vulnerabilities and agentic risk

Overview

The skill is a real Xiaomi smart-home controller, but it also handles powerful account credentials, polls lock events for occupancy-based automation, and ships household-specific identifiers with several under-scoped safety controls.

Review carefully before installing. Use only with a Xiaomi account and devices you control, pin and isolate the micloud dependency, avoid command-line passwords, rotate any password previously entered that way, protect or remove cached device and state files, and do not enable the lock-triggered fish-feeding cron unless you explicitly want occupancy-derived automation. Replace bundled home and device IDs with your own local configuration before use.

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

T08 · Insecure Dependencies

Warning
Location
SKILL.md:18
Finding
Unpinned Third-Party Dependency Executes in the Credential-Handling Process<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:18` **Vulnerability Type**: Unpinned executable dependency **Risk Level**: Medium ### Evidence ```text pip3 install micloud ``` The installed package is subsequently imported by `scripts/mijia.py:25-27`: ```python try: from micloud import MiCloud from micloud.miutils import get_session ``` ### Technical Analysis The setup instructions install the latest package published under the `micloud` name without a fixed version, cryptographic hash, lockfile, or documented source verification. The package is imported into the same process that handles the Xiaomi username, password, service token, `ssecurity` value, device inventory, and authenticated smart-home operations. This creates a supply-chain trust boundary: the behavior reviewed in this project does not fully determine the behavior executed at runtime. A compromised publisher account, malicious replacement release, or unexpectedly unsafe future release could introduce arbitrary Python code. The legitimate Xiaomi Cloud network operations are necessary for the declared functionality. However, allowing an unresolved dependency version to execute with access to account credentials exceeds the minimum safely controlled dependency surface. ### Attack Path 1. An attacker compromises the package publisher, package registry, or dependency distribution path and publishes a malicious `micloud` release. 2. A user follows the documented `pip3 install micloud` instruction. 3. The malicious package executes during installation or when imported by `scripts/mijia.py`. 4. The user runs the login or device-control command. 5. The dependency gains access to Xiaomi credentials, authenticated sessions, device identifiers, and control requests. 6. The dependency can disclose those values or perform unauthorized device operations with the user's account authority. ### Impact Assessment Successful exploitation could obtain the privileges of the user run ...[truncated 392 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin `micloud` to a specifically reviewed version. 2. Require cryptographic hashes, for example through a hash-locked requirements file. 3. Commit a dependency lockfile and review all transitive dependencies. 4. Document the expected package repository and publisher. 5. Install the dependency inside an isolated virtual environment with only the permissions required for Xiaomi Cloud operations. 6. Re-review dependency changes before updating the pinned version. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/mijia.py:62
Finding
Xiaomi Password Is Exposed Through Echoed Input and Command-Line Arguments<![CDATA[ ## Vulnerability Details **File Location**: `scripts/mijia.py:62-63, 272-274` **Vulnerability Type**: Insecure credential input **Risk Level**: High ### Evidence ```python username = args.username or input("Xiaomi username (phone): ") password = args.password or input("Xiaomi password: ") ``` ```python p_login = sub.add_parser("login", help="Login to Xiaomi Cloud") p_login.add_argument("--username", "-u") p_login.add_argument("--password", "-p") ``` ### Technical Analysis The interactive password prompt uses `input()`, which echoes the password visibly to the terminal. The parser also permits the password to be supplied through `--password` or `-p`. Command-line secrets can be retained in shell history, command transcripts, process-accounting records, terminal logs, automation logs, and, depending on the operating system, process listings visible to other local users. Echoed interactive input can also be observed through screen sharing, terminal recording, shoulder surfing, or captured console output. The Xiaomi password is only needed transiently for authentication. Exposing it through terminal echo and process arguments is not necessary for the Skill's declared functionality and violates least-exposure principles for credentials. ### Attack Path Interactive-input path: 1. The user runs the `login` command without a password argument. 2. The password is entered through `input()` and appears visibly in the terminal. 3. An observer, screen recorder, terminal logger, or shared-session participant captures it. 4. The attacker uses the password to attempt access to the Xiaomi account. Command-line path: 1. The user invokes the script with `--password` or `-p`. 2. The complete command is stored in shell history or becomes visible through process inspection or logging. 3. A local attacker or log reader retrieves the password. 4. The attacker authenticates to the account or combines the password with other account information to obtain smart-hom ...[truncated 570 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace the password prompt with a non-echoing prompt: ```python from getpass import getpass password = getpass("Xiaomi password: ") ``` 2. Remove the `--password` and `-p` command-line options. 3. If noninteractive authentication is required, use a protected secret provider or a file descriptor that does not expose the secret in process arguments. 4. Never print, log, or include the password in exception messages. 5. Clear unnecessary password references after login and retain only the minimum session credentials required. 6. Document that users should rotate the password if it was previously supplied through the command line. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/mijia.py:91
Finding
Sensitive Device Inventory Cache Is Created Without Restrictive Permissions<![CDATA[ ## Vulnerability Details **File Location**: `scripts/mijia.py:91-92` **Vulnerability Type**: Insecure sensitive-file permissions **Risk Level**: Medium ### Evidence ```python # Cache devices DEVICES_CACHE.write_text(json.dumps(devices, ensure_ascii=False, indent=2)) ``` The target is defined at `scripts/mijia.py:31`: ```python DEVICES_CACHE = Path.home() / ".mijia_devices.json" ``` ### Technical Analysis The device inventory returned by Xiaomi Cloud is written with `Path.write_text()` without requesting a restrictive creation mode and without applying `chmod(0o600)` afterward. New files are normally created using a base mode modified by the process umask. Under common umasks, this can result in a file readable by other local users. The cached response can contain device names, models, device identifiers, online status, and local IP addresses. This information maps household devices and provides local-network reconnaissance data. Unlike the credentials file, which is explicitly changed to mode `0600`, the device cache has no equivalent protection. Existing files and symbolic links are also not validated before writing, increasing the importance of secure and atomic file handling. ### Attack Path 1. The user runs `python3 scripts/mijia.py devices`. 2. Xiaomi Cloud returns the household device inventory. 3. The script writes that inventory to `~/.mijia_devices.json` using permissions derived from the current umask. 4. On a multi-user system with a permissive or common umask, another local user reads the cache. 5. The attacker learns device names, models, identifiers, online status, and potentially local IP addresses. 6. The information is used for targeted social engineering, smart-home reconnaissance, or local-network attack planning. ### Impact Assessment The file does not contain the Xiaomi password or service token based on the audited code. However, disclosure can reveal household topology, connected appliances, security-related devices ...[truncated 234 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Disable caching by default unless it is required for an explicit operation. 2. Minimize cached fields and omit local IP addresses or other unnecessary metadata. 3. Create the file atomically with mode `0600`. 4. Reject symbolic links and ensure the target is a regular file owned by the current user. 5. Apply `chmod(0o600)` to existing cache files before use. 6. Use a temporary file in the same directory, securely flush it, and atomically replace the destination. 7. Provide a command to delete the cache and document its sensitive contents. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/fish_auto_feed.py:40
Finding
Occupancy-Related Automation State Is Stored Without Restrictive Permissions<![CDATA[ ## Vulnerability Details **File Location**: `scripts/fish_auto_feed.py:40-42` **Vulnerability Type**: Insecure storage of activity metadata **Risk Level**: Medium ### Evidence ```python def save_state(state): STATE_FILE.write_text(json.dumps(state, indent=2)) ``` The stored state includes activity timestamps at `scripts/fish_auto_feed.py:137-140`: ```python state["last_feed_date"] = feed_day state["last_feed_time"] = datetime.datetime.now().isoformat() state["last_feed_success"] = success state["total_feeds"] = state.get("total_feeds", 0) + (1 if success else 0) ``` ### Technical Analysis The state file is created or overwritten without explicit restrictive permissions. Its feed timestamp is generated after the script detects a door-lock event that it interprets as the resident leaving home. Consequently, the file contains metadata correlated with occupancy and departure activity. As with the device cache, the resulting permissions depend on the process umask. On a multi-user host, the file may be readable by users who should not have access to household activity information. The write is also not atomic, so interruption could leave malformed state and affect deduplication behavior. The state file is needed for once-per-cycle deduplication, but storing a precise timestamp with default filesystem permissions exceeds the minimum data and protection needed for that purpose. ### Attack Path 1. A scheduled or manual run detects an auto-lock event. 2. The script interprets that event as the resident having left home and activates the feeder. 3. It stores `last_feed_time` and related metadata in `~/.fish_feed_state.json`. 4. Another local user reads the file if filesystem permissions permit it. 5. Repeated observations reveal timing patterns associated with household departures or automation activity. ### Impact Assessment The immediate impact is local disclosure of activity metadata. It may enable inference of occupancy schedules or recurri ...[truncated 240 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Create the state file with mode `0600` and enforce that mode on every update. 2. Write updates atomically through a protected temporary file followed by `os.replace()`. 3. Reject symbolic links and verify that existing files are regular files owned by the current user. 4. Store only the cycle date required for deduplication; remove the precise timestamp unless it is operationally necessary. 5. If detailed audit timestamps are required, document their privacy sensitivity and define a retention period. 6. Handle malformed state safely rather than silently losing deduplication guarantees. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
references/devices.json:30
Finding
Account-Specific Household Identifiers Are Embedded in the Distributed Project<![CDATA[ ## Vulnerability Details **File Location**: `references/devices.json:30` **Vulnerability Type**: Hardcoded sensitive household metadata **Risk Level**: Low ### Evidence ```json "home_id": 159001331072, ``` Additional account-specific device identifiers are hardcoded in `scripts/fish_auto_feed.py:25-29`: ```python LOCK_DID = "1175215651" LOCK_EVENT_KEY = "2.1020" FISH_DID = "2026943875" FISH_FEED_SIID = 2 FISH_FEED_AIID = 1 ``` The reference registry also associates account-specific identifiers with room names, a lock, a speaker, a router, appliances, and automation behavior. ### Technical Analysis The package contains a real-looking home identifier and multiple fixed device identifiers tied to a detailed household inventory. Device identifiers do not independently authenticate a caller, but they are account-linked metadata that should not be included in a reusable or distributable Skill. The documented functionality only requires identifiers for the current user's configured devices. They can be loaded from a protected local configuration at runtime; embedding one household's values in the project is not necessary. The data also reveals automation assumptions, including polling a specific lock event and associating it with the resident leaving home. This increases the reconnaissance value of the disclosed identifiers. ### Attack Path 1. An attacker obtains a copy of the Skill package or accesses its repository. 2. The attacker extracts the home ID, device IDs, device models, room associations, and automation details. 3. The attacker uses the information for targeted social engineering or combines it with a separate Xiaomi credential, session, API, or local-network compromise. 4. The identifiers reduce discovery effort and help the attacker target specific devices or automation behavior. ### Impact Assessment The exposed identifiers do not provide standalone authorization to Xiaomi Cloud and therefore do not directly grant device-control ...[truncated 307 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace all account-specific home and device identifiers in distributed files with placeholders. 2. Load user-specific identifiers from a local configuration file excluded from source control and package distribution. 3. Protect that configuration with mode `0600`. 4. Provide a discovery or setup command that lets users select their own devices without modifying bundled source files. 5. Remove room names, routines, and occupancy assumptions from reusable examples. 6. Review repository history and release artifacts for previously published household identifiers. 7. Treat identifier rotation or account review as appropriate if the package has already been publicly distributed. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (20)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The manifest describes an on-demand Xiaomi device control skill, but the documentation also includes unattended polling of door-lock history, leave-home inference, cron-based automation, and automated fish feeding. This hidden expansion from user-requested control to surveillance-like monitoring and autonomous actuation materially changes the trust model and can surprise users or operators.

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
This script implements autonomous behavior driven by lock telemetry rather than user-requested Xiaomi device control, which materially exceeds the declared skill purpose. In a smart-home skill, hidden automation tied to occupancy signals can create unexpected physical-world actions and erodes user consent and reviewability.

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill documents shell execution, file reads, and file writes but declares no explicit tool scope or permissions boundary. That makes the agent’s effective authority ambiguous and increases the risk of overbroad execution, especially because the skill can access credential files, write state files, and issue device-control commands.

Session Persistence

Medium
Category
Rogue Agent
Content
description: |
  Control Xiaomi Mi Home (米家) smart devices via Xiaomi Cloud API.
  Use when: user wants to control smart home devices (lights, AC, heater, bath heater, switches, etc.),
  check device status, or create automation scenes.
  Triggers: "开灯", "关灯", "开空调", "关空调", "开浴霸", "我要洗澡", "设备状态",
  "创建场景", "自动化", "米家", "smart home", "turn on/off", any home device control request.
  NOT for: non-Xiaomi devices, HomeKit-only devices.
Confidence
60% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Vague Triggers

Medium
Confidence
96% confidence
Finding
The trigger phrases are broad enough to match ordinary conversation, including generic terms like 'smart home', 'turn on/off', and 'any home device control request'. Overbroad activation can cause accidental invocation of shell-backed device actions, resulting in unintended changes to real-world devices or automations.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
**Prerequisites:** `pip3 install micloud`

**Credentials:** `~/.mijia_creds.json` (chmod 600)
```json
{"userId":"...", "serviceToken":"...", "ssecurity":"...", "cUserId":"..."}
```
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The documentation describes how to obtain and store long-lived Xiaomi session credentials, including service tokens and ssecurity values, without strong warnings about their sensitivity or handling controls. Exposure of these tokens could allow unauthorized access to the user’s Xiaomi cloud account and device fleet.

Description-Behavior Mismatch

Medium
Confidence
94% confidence
Finding
The fish-feeding workflow extends the skill from direct smart-home control into continuous polling of door-lock events and automated actuation based on inferred occupancy. This introduces privacy exposure and autonomous physical-world effects that are not obvious from the primary skill description.

Description-Behavior Mismatch

Medium
Confidence
93% confidence
Finding
The XiaoAI TTS feature adds a speaker-broadcast capability that is not declared in the manifest description or use cases. Undeclared audio output can be abused for spoofing, disruption, or privacy-invasive announcements, and users may not expect a device-control skill to speak aloud.

Context-Inappropriate Capability

Medium
Confidence
89% confidence
Finding
The registry exposes control metadata for a smart lock and router, which are materially more sensitive than ordinary lights or HVAC devices and exceed the skill’s narrowly described examples. In a home-control skill, including these identifiers increases the chance of unintended or unauthorized actions against security-critical infrastructure if prompt routing, name matching, or future tool logic is too permissive.

Context-Inappropriate Capability

Medium
Confidence
87% confidence
Finding
The scene metadata introduces a lock-event-driven fish-feeding automation that is outside the stated device-control scope and links a physical security event to an unrelated actuator. This kind of hidden cross-device automation expands behavior beyond user expectations and can create covert or unintended actions when the skill is used or extended.

Intent-Code Divergence

Medium
Confidence
90% confidence
Finding
The top-level documentation presents a successful once-per-day feeding flow, but the implementation explicitly saves `last_feed_date` regardless of API success and prints 'Will NOT retry today' on failure. That behavior contradicts the docstring's implied outcome because a failed run can still consume the day's feeding opportunity.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
The script reads smart-lock event history to infer whether the user has left home, which is sensitive occupancy/behavioral data not obviously necessary for the stated purpose of direct device control. This broadens the skill from command execution into surveillance-like inference, increasing privacy risk and enabling unintended presence tracking.

Session Persistence

Medium
Category
Rogue Agent
Content
python3 mijia.py status <did>                   # Read device properties
  python3 mijia.py set <did> <siid> <piid> <val>  # Set a device property
  python3 mijia.py get <did> <siid> <piid>        # Get a device property
  python3 mijia.py scene_create <json_file>       # Create automation scene
  python3 mijia.py scene_list                     # List automation scenes
  python3 mijia.py batch <json_file>              # Execute batch commands
Confidence
60% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The code forces `zh_CN`, `GMT+08:00`, and the `cn` server/region, which is a natural-language locale policy concern because it imposes a fixed language/locale context without opt-in. The file does not explain that this is a required region-specific tool or provide a configurable alternative.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The script reads the Xiaomi password using input(), which echoes the secret to the terminal and exposes it to shoulder surfing, screen recording, or captured terminal sessions. It also accepts --password on the command line, which can leak through shell history and process listings, making credential compromise more likely.

Description-Behavior Mismatch

Medium
Confidence
87% confidence
Finding
The manifest describes controlling Xiaomi smart home devices, checking status, and creating automation scenes, with examples like lights, AC, heaters, and switches. This function adds a separate capability to make a XiaoAI speaker speak arbitrary text, including volume/unmute/playback manipulation, which is not described in the manifest or trigger/use guidance.

Natural-Language Policy Violations

Low
Confidence
83% confidence
Finding
The `_doc` string says device lookup is performed "by Chinese name," which imposes a Chinese-language naming convention. This is a natural-language locale constraint with no indication of user choice, opt-in, or justification in the file.

Natural-Language Policy Violations

Low
Confidence
87% confidence
Finding
The default value for the scene name is the Chinese string "场景名称", which imposes a specific language in a natural-language field. Because the template does not indicate that this is optional, localized, or intended only for a Chinese-region deployment, it can violate language/locale policy expectations.

Missing User Warnings

Low
Confidence
87% confidence
Finding
The script persists feeding state to a hidden file in the user's home directory via `STATE_FILE.write_text(...)`, but there is no user confirmation around this write and the module docstring does not mention that local state will be stored. For a code file, file writes should have at least some visible disclosure through comments, logging, or documentation unless clearly warned elsewhere.

Static analysis

No suspicious patterns detected.