Back to skill

Security audit

Homeassistant Skill

Security checks for vulnerabilities and agentic risk

Overview

This skill is transparent about controlling Home Assistant, but it needs review because it uses a long-lived smart-home token for broad private-data access and high-impact actions with incomplete guardrails.

Install only if you are comfortable giving an agent broad Home Assistant authority. Use HTTPS, create the least-privileged dedicated Home Assistant user/token you can, avoid exposing tokens or alarm codes in chat or shell history, and require explicit confirmation before scripts, automations, notifications, TTS, calendar/presence reads, locks, alarms, covers, or any generic service/template action.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:20
Finding
Long-Lived Home Assistant Bearer Token May Be Transmitted over Plaintext HTTP<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:20,39-40`; `README.md:41,76-79` **Vulnerability Type**: Plaintext transmission of a long-lived authentication credential **Risk Level**: Medium ### Vulnerable Code `SKILL.md:20`: ```markdown - `HA_URL` — Your Home Assistant URL (e.g., `http://10.0.0.10:8123`) ``` `SKILL.md:39-40`: ```bash curl -s "$HA_URL/api/states" -H "Authorization: Bearer $HA_TOKEN" \ | jq -r '.[].entity_id' | sort ``` `README.md:41`: ```bash export HA_URL=http://10.0.0.10:8123 ``` `README.md:76-79`: ```bash curl -s -X POST "$HA_URL/api/services/light/turn_on" \ -H "Authorization: Bearer $HA_TOKEN" \ -H "Content-Type: application/json" \ -d '{"entity_id": "light.office", "brightness_pct": 80}' ``` ### Technical Analysis The documentation recommends an HTTP Home Assistant URL while instructing the Agent to send a long-lived bearer token in the `Authorization` header. Plain HTTP does not provide transport encryption, integrity protection, or server authentication. An attacker with visibility or control over the network path could capture the bearer token through passive traffic inspection or obtain it through an active man-in-the-middle attack. Because bearer authentication requires only possession of the token, an intercepted token can be replayed without knowing any additional credential. The exposure is particularly significant because the documentation states that Home Assistant long-lived tokens do not expire automatically. The same token is used for state queries and service calls involving private household information and physical devices. ### Attack Path 1. A user follows the documented configuration and sets `HA_URL` to an `http://` endpoint. 2. The skill sends a request containing `Authorization: Bearer $HA_TOKEN`. 3. An attacker on the same wireless network, compromised router, proxy, or other network path observes or modifies the plaintext request. 4. The attacker extracts the bearer token from ...[truncated 1056 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace all recommended `http://` URLs with `https://` URLs. 2. State explicitly that bearer tokens must not be transmitted over plaintext HTTP. 3. Validate `HA_URL` before making requests and reject non-HTTPS schemes by default. 4. If development access over plaintext is unavoidable, restrict it to an explicit loopback-only mode and display a security warning. 5. Preserve normal TLS certificate verification; do not recommend `curl -k` or `--insecure`. 6. Document secure deployment options for local Home Assistant installations, such as a trusted reverse proxy, a locally trusted certificate authority, or a secure VPN. 7. Recommend creating a dedicated, least-privileged Home Assistant account or token for the skill. 8. Document token revocation and rotation procedures following suspected disclosure. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
SKILL.md:331
Finding
Alarm Disarm Example Contains a Common Hardcoded PIN<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:331-334` **Vulnerability Type**: Hardcoded security credential in an executable example **Risk Level**: Low ### Vulnerable Code ```bash curl -s -X POST "$HA_URL/api/services/alarm_control_panel/alarm_disarm" \ -H "Authorization: Bearer $HA_TOKEN" \ -H "Content-Type: application/json" \ -d '{"entity_id": "alarm_control_panel.home", "code": "1234"}' ``` ### Technical Analysis The alarm-disarm example contains the literal code `1234`, a commonly used weak PIN, in a directly executable service request. It is not represented as an unmistakable placeholder or securely supplied secret. An Agent following the skill instructions may execute the example against a real alarm panel. If the target system uses the same weak code, the request could successfully disarm it. The example may also encourage users to configure or retain a predictable PIN. When users replace the value directly in the command, the actual alarm code may be exposed through shell history, Agent transcripts, process inspection, command logging, or diagnostic output. The safety instruction requiring user confirmation reduces accidental execution risk but does not address insecure credential handling. ### Attack Path 1. A Home Assistant alarm panel is configured with the common PIN `1234`, or a user copies the example without replacing the value. 2. An authenticated Agent or user runs the documented `alarm_disarm` command after confirmation. 3. Home Assistant forwards the literal PIN to the configured alarm integration. 4. If the panel accepts that PIN, the alarm is disarmed. 5. Alternatively, a user substitutes a real PIN directly into the command, after which it may persist in command history, logs, or Agent conversation records. 6. Anyone who can access those records may recover and reuse the alarm code. ### Impact Assessment Successful exploitation can disarm the targeted alarm control panel. The affected scope is limited t ...[truncated 420 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace the literal PIN with a clearly unresolved secret reference: ```bash -d "{\"entity_id\":\"alarm_control_panel.home\",\"code\":\"${HA_ALARM_CODE}\"}" ``` 2. Require the command to abort if the secret variable is unset: ```bash : "${HA_ALARM_CODE:?HA_ALARM_CODE must be supplied securely}" ``` 3. Do not place the alarm code in documentation, source files, Agent prompts, or ordinary shell history. 4. Prefer a protected secret manager, securely scoped environment variable, or interactive secret input that suppresses terminal echo. 5. Ensure request headers, bodies, and expanded commands are excluded from debug and audit logs. 6. Explicitly warn users not to use common PINs such as `1234`. 7. Retain the existing explicit-confirmation requirement for all alarm arming and disarming operations. 8. Recommend rotating the alarm PIN immediately if it has appeared in logs, transcripts, or shell history. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (19)

Credential Access

High
Category
Privilege Escalation
Content
## Configuration

1. Create a long-lived access token in Home Assistant: Profile → Long-Lived Access Tokens
2. Set environment variables:

```bash
Confidence
90% confidence
Finding
The reference to Home Assistant long-lived access tokens indicates credential use for a skill that can interact with numerous sensitive smart-home domains. Because the README lacks warnings about credential scope and the consequences of token theft, it understates the security risk of provisioning persistent credentials to an agent-integrated skill.

Credential Access

High
Category
Privilege Escalation
Content
## Configuration

1. Create a long-lived access token in Home Assistant: Profile → Long-Lived Access Tokens
2. Set environment variables:

```bash
Confidence
90% confidence
Finding
The reference to Home Assistant long-lived access tokens indicates credential use for a skill that can interact with numerous sensitive smart-home domains. Because the README lacks warnings about credential scope and the consequences of token theft, it understates the security risk of provisioning persistent credentials to an agent-integrated skill.

Credential Access

High
Category
Privilege Escalation
Content
Set environment variables:
- `HA_URL` — Your Home Assistant URL (e.g., `http://10.0.0.10:8123`)
- `HA_TOKEN` — Long-lived access token (create in HA → Profile → Long-Lived Access Tokens)

## Safety Rules
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
Set environment variables:
- `HA_URL` — Your Home Assistant URL (e.g., `http://10.0.0.10:8123`)
- `HA_TOKEN` — Long-lived access token (create in HA → Profile → Long-Lived Access Tokens)

## Safety Rules
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The README explicitly advertises access to person/presence and device location data but provides no privacy warning, consent guidance, or data-handling limitations. In a smart-home skill, presence and location data are highly sensitive because they can reveal occupancy patterns and whether a home is unattended.

External Transmission

Medium
Category
Data Exfiltration
Content
```bash
# "Turn on the office light at 80%"
curl -s -X POST "$HA_URL/api/services/light/turn_on" \
  -H "Authorization: Bearer $HA_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"entity_id": "light.office", "brightness_pct": 80}'
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Vague Triggers

Medium
Confidence
95% confidence
Finding
The phrase 'Use when the user asks about their smart home, devices, or automations' is broad and overlaps with many ordinary conversational requests. It does not clearly define boundaries, exclusions, or specific trigger phrases, which could cause unintended activation for general device-related discussion.

External Transmission

Medium
Category
Data Exfiltration
Content
### Get single entity state

```bash
curl -s "$HA_URL/api/states/ENTITY_ID" -H "Authorization: Bearer $HA_TOKEN"
```

### Area & Floor Discovery
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
-d '{"template": "{{ area_entities(\"kitchen\") | select(\"match\", \"light.\") | list }}"}'

# Find which area an entity belongs to
curl -s -X POST "$HA_URL/api/template" \
  -H "Authorization: Bearer $HA_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"template": "{{ area_name(\"light.kitchen\") }}"}'
Confidence
78% confidence
Finding
The template endpoint evaluates server-side Jinja2, and the skill includes a generic mechanism for sending template strings. If user-controlled template content is passed through, it can expand data access beyond intended entity reads and enable broad enumeration of areas, devices, labels, and states, increasing privacy and overreach risk.

External Transmission

Medium
Category
Data Exfiltration
Content
| jq -r '.[] | select(.entity_id | startswith("script.")) | "\(.entity_id): \(.state)"'

# Run a script
curl -s -X POST "$HA_URL/api/services/script/turn_on" \
  -H "Authorization: Bearer $HA_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"entity_id": "script.bedtime_routine"}'
Confidence
87% confidence
Finding
Running scripts can trigger arbitrary bundled actions inside Home Assistant, including actions affecting locks, alarms, notifications, and other physical devices. The skill does not require inspection or confirmation of script contents before execution, so a seemingly benign script name could cause sensitive side effects.

External Transmission

Medium
Category
Data Exfiltration
Content
| jq -r '.[] | select(.entity_id | startswith("automation.")) | "\(.entity_id): \(.state)"'

# Trigger an automation
curl -s -X POST "$HA_URL/api/services/automation/trigger" \
  -H "Authorization: Bearer $HA_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"entity_id": "automation.morning_routine"}'
Confidence
91% confidence
Finding
Triggering automations can execute complex action chains with physical and security impact, and enabling/disabling automations can alter safety controls. Because automation behavior is opaque from the command alone, this creates a high risk of unsafe or security-relevant actions being performed without sufficient guardrails.

External Transmission

Medium
Category
Data Exfiltration
Content
| jq '{state: .state, current_temp: .attributes.current_temperature, target_temp: .attributes.temperature}'

# Set temperature
curl -s -X POST "$HA_URL/api/services/climate/set_temperature" \
  -H "Authorization: Bearer $HA_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"entity_id": "climate.thermostat", "temperature": 72}'
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
| jq -r '.[] | select(.domain == "notify") | .services | keys[]' | sort

# Send a notification to a mobile device
curl -s -X POST "$HA_URL/api/services/notify/mobile_app_phone" \
  -H "Authorization: Bearer $HA_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"message": "Front door opened", "title": "Home Alert"}'
Confidence
74% confidence
Finding
The notification capability can transmit potentially sensitive household events and alerts to mobile devices or broad notify targets. Without guidance on confirmation, recipient validation, or data minimization, it could be used to leak private status information to unintended endpoints.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The skill exposes person and device_tracker queries that reveal occupancy and location information, but the markdown does not warn that these data are privacy-sensitive. Presence data can be used to infer when a home is empty or where occupants are located, which materially raises stalking, burglary, and surveillance risks.

External Transmission

Medium
Category
Data Exfiltration
Content
| jq '{state: .state, temperature: .attributes.temperature, humidity: .attributes.humidity, wind_speed: .attributes.wind_speed}'

# Get forecast (daily)
curl -s -X POST "$HA_URL/api/services/weather/get_forecasts" \
  -H "Authorization: Bearer $HA_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"entity_id": "weather.home", "type": "daily"}'
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
Calendar retrieval can disclose private schedules, travel, meetings, and household routines, yet the documentation presents it as a normal read operation with no privacy warning. In a home-automation context, schedule data can also be combined with presence or lock information to infer when occupants will be away.

External Transmission

Medium
Category
Data Exfiltration
Content
## Text-to-Speech

```bash
curl -s -X POST "$HA_URL/api/services/tts/speak" \
  -H "Authorization: Bearer $HA_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"entity_id": "tts.google_en", "media_player_entity_id": "media_player.living_room_speaker", "message": "Dinner is ready"}'
Confidence
76% confidence
Finding
Text-to-speech can broadcast arbitrary spoken messages into the home environment, which can cause harassment, social engineering, or unsafe distraction, especially if sent unexpectedly to shared speakers. In some environments it may also reveal private information aloud to bystanders.

External Transmission

Medium
Category
Data Exfiltration
Content
The `/api/template` endpoint evaluates Jinja2 templates server-side. Useful for computed queries.

```bash
curl -s -X POST "$HA_URL/api/template" \
  -H "Authorization: Bearer $HA_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"template": "TEMPLATE_STRING"}'
Confidence
88% confidence
Finding
A generic '/api/template' interface effectively grants powerful read/query capabilities over the Home Assistant state model through server-side template evaluation. This is more dangerous than ordinary entity reads because it can aggregate and enumerate data broadly, potentially bypassing intended per-feature restrictions and increasing privacy exposure.

External Transmission

Medium
Category
Data Exfiltration
Content
-d '{"template": "{{ states.light | list | count }} lights"}'

# Get entity state in a template
curl -s -X POST "$HA_URL/api/template" \
  -H "Authorization: Bearer $HA_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"template": "{{ states(\"light.living_room\") }}"}'
Confidence
86% confidence
Finding
This example demonstrates direct template-based state extraction, reinforcing that the skill supports arbitrary server-side template queries. Such capability can be abused to enumerate entity states at scale, correlate sensitive data, and retrieve more information than the user may have explicitly requested.

Static analysis

No suspicious patterns detected.