T09 · Insecure Skill Coding Practices
- Location
SKILL.md:89- Finding
TLS Certificate Verification Disabled for Authenticated Home Assistant Requests
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This Home Assistant skill is purpose-aligned, but it needs Review because its default setup uses a long-lived smart-home token with insecure TLS and limited technical safeguards.
Install only if you are comfortable giving OpenClaw a long-lived Home Assistant token. Use a dedicated non-admin Home Assistant user with the smallest possible device/entity access, remove curl -k unless you have explicitly configured trusted certificates another way, avoid storing the token in shell profiles, lock down any token file permissions, and revoke/rotate the token if exposed.
SKILL.md:89TLS Certificate Verification Disabled for Authenticated Home Assistant Requests
SKILL.md:51Long-Lived Home Assistant Token Stored in Plaintext Without File-Permission Hardening
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
- `curl` on PATH
- A running Home Assistant instance with HTTPS access
- A **restricted (non-admin)** HA user with a Long-Lived Access Token
> **Note:** If your HA instance uses a self-signed certificate, the skill uses curl's `-k` flag to allow the connection. If you use a trusted certificate (e.g. Let's Encrypt), you can remove the `-k` flag from the curl command in `SKILL.md`.
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
- `curl` on PATH
- A running Home Assistant instance with HTTPS access
- A **restricted (non-admin)** HA user with a Long-Lived Access Token
> **Note:** If your HA instance uses a self-signed certificate, the skill uses curl's `-k` flag to allow the connection. If you use a trusted certificate (e.g. Let's Encrypt), you can remove the `-k` flag from the curl command in `SKILL.md`.
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
### 1. Set Up Home Assistant
1. Create a non-admin user in HA (e.g. `openclaw-bot`) via **Settings > People > Add Person**
2. Log in as that user and go to **Profile > Long-Lived Access Tokens > Create Token**
3. Copy the token immediately
### 2. Install the Skill
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
### 1. Set Up Home Assistant
1. Create a non-admin user in HA (e.g. `openclaw-bot`) via **Settings > People > Add Person**
2. Log in as that user and go to **Profile > Long-Lived Access Tokens > Create Token**
3. Copy the token immediately
### 2. Install the Skill
This section accurately notes a real security caveat: the Home Assistant long-lived token is not scoped to only the conversation endpoint, so compromise of the token would allow access to any API endpoints permitted to that user. In this skill's context, the danger is reduced by using a restricted non-admin account, but the control is procedural rather than technically enforced by the credential itself.
- The token should belong to a **non-admin** user with limited area/entity access
- The token is **never** echoed or logged by the skill
- If Assist can't handle a request, the skill reports the error rather than falling back to other API calls
- **Important caveat:** The Long-Lived Access Token is not technically scoped to the Conversation API — it grants access to all HA API endpoints available to that user. The endpoint restriction is enforced by the skill instructions, not by the token itself. This is why using a **restricted non-admin user** is critical — it limits the blast radius even if the token is misused
### Trusted Networks Warning
The skill forwards arbitrary 'USER REQUEST HERE' text directly to Home Assistant's Assist API, meaning untrusted user input becomes a privileged device-control action with no local validation or allowlisting. Although the skill limits calls to a single endpoint and recommends a restricted HA user, a malicious or unsafe prompt could still trigger unintended actions on all entities that account can control.
Send any smart home command in natural language. The skill passes it directly to HA Assist:
curl -sk -X POST "$HOME_ASSISTANT_URL/api/conversation/process" \
-H "Authorization: Bearer $HOME_ASSISTANT_TOKEN" \
-H "Content-Type: application/json" \
-d '{"text": "USER REQUEST HERE", "language": "DETECTED LANGUAGE CODE"}'
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.
### 1. Set Up Home Assistant
1. Create a non-admin user in HA (e.g. `openclaw-bot`) via **Settings > People > Add Person**
2. Log in as that user and go to **Profile > Long-Lived Access Tokens > Create Token**
3. Copy the token immediately
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.
## Setup
### 1. Create a Restricted Home Assistant User
1. In Home Assistant go to **Settings → People → Add Person**
2. Create a new user (e.g. `openclaw-bot`)
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
Send any smart home command in natural language. The skill passes it directly to HA Assist:
curl -sk -X POST "$HOME_ASSISTANT_URL/api/conversation/process" \
-H "Authorization: Bearer $HOME_ASSISTANT_TOKEN" \
-H "Content-Type: application/json" \
-d '{"text": "USER REQUEST HERE", "language": "DETECTED LANGUAGE CODE"}'
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.
Many languages use grammatical cases or word inflection, causing entity names to change form in natural speech. Home Assistant entity names are typically in their base/dictionary form (nominative), but users naturally use other grammatical forms in commands.
This affects languages including (but not limited to):
- **Polish** — 7 cases (e.g. *drukarkę* → *drukarka*, *lampę* → *lampa*)
- **Czech** — 7 cases (e.g. *tiskárnu* → *tiskárna*, *lampu* → *lampa*)
- **German** — 4 cases + articles (e.g. *den Drucker* → *Drucker*, *die Lampe* → *Lampe*)
No suspicious patterns detected.