Back to skill

Security audit

Aqara Agent

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its Aqara smart-home purpose, but it handles a live home-control API key and device-changing actions with several under-scoped safety and secret-handling risks.

Install only if you trust the publisher and are comfortable giving the skill an Aqara API key that can read and change smart-home state. Prefer a least-privilege or revocable key, avoid custom API endpoint overrides unless you fully trust them, restrict permissions on user_account.json, and review device-control, firmware, scene, and automation actions before letting an agent run them.

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)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/aqara_open_api.py:38
Finding

Authenticated API Requests Can Be Redirected to an Arbitrary Endpoint

Content
View full analysis
str: """Resolve Open Platform REST base URL (no trailing slash).""" if explicit is not None and str(explicit).strip(): return str(explicit).strip().rstrip("/") env_url = (os.environ.get("AQARA_OPEN_API_URL") or "").strip() if env_url: return env_url.rstrip("/") disk_url = load_optional_open_api_base_url() if disk_url: return disk_url.rstrip("/") return _default_api_base_url() ``` The selected URL is subsequently used with the bearer credential: ```python self.api_key = key self.base_url = _resolve_api_base_url(api_base_url) self.session = requests.Session() self.session.headers.update({"application_id": "AqaraAgentSkills"}) self.session.headers.update({"Authorization": f"Bearer {key}"}) if home_id and str(home_id).strip(): self.session.headers.update({"position_id": str(home_id).strip()}) ``` The disk override is read from the credential file without validation: ```python def load_optional_open_api_base_url() -> Optional[str]: """ Optional full REST base URL from ``assets/user_account.json`` (e.g. local proxy). Tried in order: ``aqara_open_api_url``, ``open_api_url``. Whitespace-only values are ignored. """ _migrate_legacy_user_context_file() if not USER_ACCOUNT_PATH.exists(): return None try: data = json.loads(USER_ACCOUNT_PATH.read_text(encoding="utf-8")) if not isinstance(data, dict): return None for key in ("aqara_open_api_url", "open_api_url"): v = data.get(key) if isinstance(v, str) and v.strip(): return v.strip() return None ...[truncated 2225 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/runtime_utils.py:187
Finding

Sensitive Credential File Is Written Without Enforcing Restrictive Permissions

Content
View full analysis
None: """ Merge-write aqara_api_key and updated_at; keep other keys in user_account.json. Remove legacy keys aqara_access_token and region; after success, delete legacy pairing images under assets if any. """ _migrate_legacy_user_context_file() api_key = (api_key or "").strip() if not api_key: raise ValueError("aqara_api_key must be non-empty") data = _load_user_account_dict_or_template() data.pop("region", None) data.pop("aqara_access_token", None) data["aqara_api_key"] = api_key data["updated_at"] = datetime.now(timezone.utc).isoformat() ASSETS_DIR.mkdir(parents=True, exist_ok=True) USER_ACCOUNT_PATH.write_text( json.dumps(data, ensure_ascii=False, indent=2) + "\n", encoding="utf-8", ) _unlink_legacy_pairing_artifacts() ``` Home-context updates use the same unrestricted write mechanism: ```python def merge_user_context_home_info( homes: Optional[List[Dict[str, Any]]] = None, position_ids: Optional[Dict[str, str]] = None, home_id: Optional[str] = None, home_name: Optional[str] = None, ) -> None: """ Merge home fields into user_account.json; preserve existing aqara_api_key and other keys. Drops obsolete region (region is derived from the token on the server; this skill no longer persists region). """ _migrate_legacy_user_context_file() data = _load_user_account_dict_or_template() if homes is not None: data["homes"] = homes if position_ids is not None: data["position_ids"] = position_ids if home_id is not None: data["home_id"] = str(home_id).strip() if home_name is not None: data["home_name"] = str(home_name).strip() ...[truncated 1954 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
references/aqara-account-manage.md:33
Finding

Normative Login Workflow Exposes the API Credential Through Process Arguments

Content
View full analysis
' ``` The command implementation accepts that positional secret: ```python def _cmd_api_key(args: argparse.Namespace) -> int: if args.file is not None: raw = args.file.read_text(encoding="utf-8") elif args.api_key is not None: raw = args.api_key else: raw = sys.stdin.read() api_key = (raw or "").strip() if not api_key: print_json({"ok": False, "message": "api_key is empty"}) return 2 if args.dry_run: print_json({"ok": True, "dry_run": True, "aqara_api_key_length": len(api_key)}) return 0 try: set_aqara_api_key(api_key) except ValueError as e: print_json({"ok": False, "message": str(e)}) return 2 ``` ```python pk.add_argument( "api_key", nargs="?", default=None, help="API key; omit to read from stdin (stripped)", ) ``` ### Technical Analysis Command-line arguments are not an appropriate transport for bearer credentials. Depending on the operating system and execution environment, arguments can be exposed through process listings, `/proc`, shell history, terminal recording, audit logs, Agent tool logs, crash reports, or endpoint-monitoring software. Although the script supports stdin and file input, the normative Skill workflow explicitly directs the Agent to use the positional argument. This makes the safer input mechanism unlikely to be used during normal operation. Shell quoting mitigates command injection from many special characters, but i ...[truncated 1102 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Note
Location
scripts/requirements.txt:1
Finding

Unbounded Dependency Version Prevents Reproducible and Reviewed Installation

Content
View full analysis
=2.28 ``` The Skill directs installation from this file: ```bash pip install -r scripts/requirements.txt ``` ### Technical Analysis The requirement specifies only a minimum version and accepts any future release of `requests`. It also leaves transitive dependencies to be resolved dynamically. Therefore, two installations performed at different times can execute different third-party code without any change to the audited Skill package. No suspicious package name, alternate package index, remote source archive, or known malicious dependency was identified. The finding is a supply-chain and reproducibility weakness rather than evidence that the current dependency is malicious. ### Attack Path 1. A future direct or transitive dependency release is compromised, malicious, or unexpectedly incompatible. 2. A user follows the Skill instructions and runs `pip install -r scripts/requirements.txt`. 3. The package resolver selects the unreviewed release because it satisfies `requests>=2.28`. 4. Installation or later Skill execution loads the affected third-party code. 5. That code runs with the privileges of the Agent process and may access local files, environment variables, or network resources available to that process. ### Impact Assessment The maximum impact is code execution with the privileges of the Python installation or Agent process. In the context of this Skill, such code could potentially access `assets/user_account.json` and its Aqara credential. Actual exploitation requires compromise or malicious behavior in a future accepted dependency release; no such malicious component was established by this audit. ]]>
Remediation
View remediation
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • 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
Findings (28)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The manifest presents the skill as a natural-language home-management agent, but the documented behavior also includes persisting API credentials and home-selection state to a live local file. This mismatch can bypass user and platform expectations about sensitive data handling, causing credential storage and state mutation to occur in a skill that does not clearly declare those side effects.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
human index only) when present in a pack; **Forbidden** treat it as overriding `SKILL.md`.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
human index only) when present in a pack; **Forbidden** treat it as overriding `SKILL.md`.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
human index only) when present in a pack; **Forbidden** treat it as overriding `SKILL.md`.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
-workflow/` | NL -> `raw_config` -> create; **Files (scan):** `manifest.json`, `step-01-conditions-actions-extract.md`, `step-02-cell-info-fill.md`, `step-03-pa

Missing User Warnings

High
Category
Not specified by scanner
Confidence
94% confidence
Finding

The storage note explicitly documents that the pasted aqara_api_key is stored in user_account.json, but there is no corresponding user-facing notice about persistence, protection, or operational safeguards. This creates unnecessary exposure of a high-value secret and increases the chance of accidental disclosure through files, logs, backups, debugging, or downstream tooling.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
96% confidence
Finding

This file operationalizes credential collection by directing the user to obtain an Aqara API access credential and paste it into chat for automatic saving. Given the skill’s capabilities to query and control smart-home devices and automations, successful credential capture could permit unauthorized observation of home state and manipulation of connected devices.

Content

Scanner excerpt · assets/login_reply_prompt.json (reported line 12)May include surrounding context.

json
"supported_locales": ["en", "zh", "ja", "ko", "de", "es", "ru", "pt", "ar"],
  "locales": {
    "en": {
      "instruction_paragraph": "Click or copy the link below to open the Aqara sign-in page in your browser. After you sign in successfully, you will receive an Aqara API access credential (aqara_api_key). Paste the aqara_api_key value into this chat and I will save it for you automatically.",
      "api_key_saved_message": "aqara_api_key saved successfully."
    },
    "zh": {

Missing User Warnings

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The prompt instructs users to paste a live Aqara API credential directly into chat and says it will be saved automatically, but gives no warning about sensitivity, storage, retention, scope, or safe handling. In a home-automation skill, that credential may enable broad access to devices, scenes, automations, logs, and energy data, so mishandling could lead to privacy loss and unauthorized control of physical systems.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill instructs the agent to use environment variables, read and write local files, and make outbound network requests, but it does not declare any explicit tool scope or permission boundaries. That creates an over-privileged execution model where a host may grant broad capabilities without clear consent or enforcement, increasing the blast radius if the skill is misused, compromised, or prompt-injected.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The description includes many broad natural-language examples that map directly to impactful actions such as device control, firmware upgrades, scene execution, and automation creation, but it does not define clear activation constraints or confirmation gates. In an agentic environment, that raises the risk of accidental triggering from ambiguous conversation or maliciously crafted text that resembles a supported command.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill enables real-world actions with safety consequences, including controlling home devices, executing scenes, creating automations, and upgrading firmware, yet the documentation lacks a prominent warning or policy for confirming dangerous operations. In a smart-home context, accidental or coerced execution could affect physical security, privacy, power usage, or device availability.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The fallback policy explicitly requires always using English whenever the user's language is unknown, ambiguous, or unsupported. This is a natural-language locale policy constraint that does not offer user choice or opt-in, which matches the policy-violation category for forced language behavior.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The instruction requires sub_query, name, and other free-text fields to match the input query language exactly. This is a natural-language locale policy constraint that forces a specific language behavior based solely on input, with no explicit user choice or opt-in mechanism documented.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The routing rule says wording is not limited to fixed example sentences and to classify based on whether natural language or intent falls into broad categories like scheduled or delayed device/scene control. Because it does not provide explicit trigger boundaries or negative examples, ordinary requests about doing something later could be routed into automation creation too broadly.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
75% 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.

Content

Scanner excerpt · references/home-space-manage.md (reported line 31)May include surrounding context.

md
### Step 2: Single Home

- **Must** write `home_id` / `home_name` to `user_account.json` without asking.

### Step 3: Rooms

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The markdown explicitly requires location_en to use geographic place names in English. This imposes a language-specific constraint in user-facing behavior without indicating user choice, opt-in, or a documented policy justification for forcing English.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

This code exposes operations such as device control, firmware upgrade, scene execution/creation, and automation switching/creation that can alter the user's home state, but the implementation provides no confirmation prompt and no user-facing disclosure at invocation time beyond terse method docstrings. For safety-critical code paths, the rule calls for some visible warning or disclosure unless clearly covered elsewhere; in this file, those potentially impactful actions are performed silently once called.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The manifest describes a home automation skill for querying and controlling Aqara homes, scenes, automations, ambience, and energy statistics. This script adds a separate capability to ingest and persist the Aqara API key into assets/user_account.json, which is a credential-management operation not described as part of the skill's user-facing scope.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
85% confidence
Finding

This markdown file applies to SQP-2 and explicitly instructs the system to write home_id and home_name to user_account.json without asking. While the behavior may be part of the workflow, the description does not provide any user-facing warning that account data will be stored locally or updated automatically.

Content

No source excerpt is available for this finding.

Scope Creep

Low
Category
Excessive Agency
Confidence
70% confidence
Finding

Skill's behavior or capabilities extend beyond its stated purpose. Scope creep allows an agent to perform actions unrelated to its documented functionality, increasing the attack surface.

Content

Scanner excerpt · references/automation-manage.md (reported line 27)May include surrounding context.

md
## Not immediate catalog execute (routing)

**Scheduled scene control** and **delayed scene control** (time or clock condition + run an **existing catalog scene**, and **not** immediate **`post_execute_scene`**): whenever NL / intent falls here, semantically this is equivalent to **creating an automation** (action is scene execution; see **`automation-create-workflow`** action intent **3** and [`automation-create.md`](automation-create.md)), **Must** **go straight to** [`automation-create.md`](automation-create.md), **Forbidden** to replace the primary path with the immediate flow in [`scene-workflow/execute.md`](scene-workflow/execute.md) or host timers that only defer `post_execute_scene`. Wording is not limited to fixed example sentences; classify by whether intent falls in the above category.

## Scene name matching (shared)

Scope Creep

Low
Category
Excessive Agency
Confidence
70% confidence
Finding

Skill's behavior or capabilities extend beyond its stated purpose. Scope creep allows an agent to perform actions unrelated to its documented functionality, increasing the attack surface.

Content

Scanner excerpt · references/scene-manage.md (reported line 9)May include surrounding context.

md
## Not immediate catalog execute (routing)

**Scheduled scene control** and **delayed scene control** (time or clock condition + run an **existing catalog scene**, and **not** immediate **`post_execute_scene`**): whenever NL / intent falls here, semantically this is equivalent to **creating an automation** (action is scene execution; see **`automation-create-workflow`** action intent **3** and [`automation-create.md`](automation-create.md)), **Must** **go straight to** [`automation-create.md`](automation-create.md), **Forbidden** to replace the primary path with the immediate flow in [`scene-workflow/execute.md`](scene-workflow/execute.md) or host timers that only defer `post_execute_scene`. Wording is not limited to fixed example sentences; classify by whether intent falls in the above category.

## Scene name matching (shared)

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The file instructs the skill to choose the snapshot name casing/default based on AQARA_DEFAULT_LOCALE, rather than offering the user a language or locale choice. This is a natural-language locale policy concern because output behavior is determined by a preset locale with no explicit opt-in in the skill instructions.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
96% confidence
Finding

The get_homes method hard-codes a default lang value of "zh" and writes it into request headers when no user choice is supplied. This imposes a specific locale by default, and the file does not present an opt-in, choice mechanism, or justification for why Chinese is required.

Content

No source excerpt is available for this finding.

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Confidence
50% confidence
Finding

Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Content

Scanner excerpt · scripts/aqara_open_api.py (reported line 423)May include surrounding context.

python
if method_name.startswith("_"):
        print(f"Unknown tool: {method_name}", file=sys.stderr)
        sys.exit(1)
    meth = getattr(api, method_name, None)
    if not callable(meth):
        print(f"Unknown tool: {method_name}", file=sys.stderr)
        sys.exit(1)

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
94% confidence
Finding

The dependency is specified as requests>=2.28 without an upper bound or exact pin, which makes builds non-reproducible and can pull in unexpected versions over time. In a home-automation agent, dependency drift can introduce known vulnerable or incompatible releases into code that may handle credentials, device control, and user data.

Content

Scanner excerpt · scripts/requirements.txt (reported line 1)May include surrounding context.

text
requests>=2.28

Static analysis

No suspicious patterns detected.