T09 · Insecure Skill Coding Practices
- Location
scripts/entities.sh:8- Finding
Long-Lived Home Assistant Token May Be Transmitted over Plaintext HTTP
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This Home Assistant skill is mostly purpose-aligned, but it should be reviewed carefully because it stores and sends a long-lived home-control token, documents plain HTTP, and can change real devices without built-in safeguards.
Install only if you trust the host running OpenClaw and your Home Assistant token is limited and revocable. Prefer an HTTPS Home Assistant URL, protect ~/.openclaw/credentials/homeassistant.json with strict permissions, avoid administrator tokens where possible, and treat write commands as real device changes.
scripts/entities.sh:8Long-Lived Home Assistant Token May Be Transmitted over Plaintext HTTP
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
## Requirements
- Home Assistant instance (local or remote)
- Long-lived access token from HA profile
- `curl` and `jq` installed
## Setup
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
## Requirements
- Home Assistant instance (local or remote)
- Long-lived access token from HA profile
- `curl` and `jq` installed
## Setup
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
## Setup
1. Generate a long-lived access token in Home Assistant:
- Profile (bottom left) → Long-Lived Access Tokens → Create Token
- Name it "clawd" or similar
2. Create credentials file at `~/.openclaw/credentials/homeassistant.json`:
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
## Setup
1. Generate a long-lived access token in Home Assistant:
- Profile (bottom left) → Long-Lived Access Tokens → Create Token
- Name it "clawd" or similar
2. Create credentials file at `~/.openclaw/credentials/homeassistant.json`:
The code does interact with Home Assistant via REST API, which aligns with the general domain. However, the supplied chunk only supports climate entities: setting temperature, setting HVAC mode, and retrieving climate status. The declared description says the skill supports climate, light, switch, and sensor queries, which overstates the implemented capabilities for this code chunk. Additionally, the script reads URL and token from a local credentials file in the user's home directory, a resource access detail not reflected in the declaration. The primary purpose is therefore narrower than declared, making the description inaccurate for this code chunk.
The description says the skill controls Home Assistant entities via REST API and is intended for actions on lights, climate, switches, and similar entities, while also mentioning sensor queries. The supplied code only performs a GET request to /api/states and formats/filter results for listing or searching entities. There are no POST/service-call operations to turn devices on/off, set temperature, or otherwise control entities. So the primary implemented behavior is querying/listing/searching entity state, not controlling devices. Accessing Home Assistant is consistent with the described resource, but the functional emphasis is materially different from the declared control capability.
The code is clearly limited to light entity operations in Home Assistant. It uses the light service endpoints to turn lights on/off/toggle, set brightness, set RGB color, and fetch entity state. While this partially fits the declared purpose of controlling Home Assistant entities via REST API, the description materially overstates the implemented scope by claiming support for climate, switch, and sensor queries. There is no code for thermostat/climate services, switch services, or dedicated sensor handling. Resource access and overall domain are consistent with Home Assistant, but the implemented capability is narrower than declared.
The description says this skill controls Home Assistant entities such as lights, climate, and switches, while also supporting sensor queries. The supplied code chunk is a read-only sensor/state lookup script: it reads Home Assistant credentials, issues a GET request to /api/states/{entity}, and prints the returned state. There is no POST/service-call logic or any mechanism to control lights, thermostats, or switches. Although sensor queries are consistent with part of the description, the primary declared purpose of control is not represented by this code chunk, making this a material description-behavior mismatch.
The code does interact with Home Assistant via REST API as described, but its implemented scope is materially narrower than the declared description. It only defines switch-domain control services (turn_on, turn_off, toggle) and a generic state lookup command. There is no implementation for climate/thermostat operations, no light-domain service calls, and no dedicated broader entity control logic. Because the declared purpose explicitly presents support for multiple Home Assistant domains that are not implemented in this code chunk, the description does not accurately represent the actual behavior.
The skill explicitly relies on a long-lived access token stored in a local credentials file, which is a sensitive secret granting authenticated control over Home Assistant. Persistent bearer tokens materially increase the blast radius of file disclosure, logging mistakes, prompt exfiltration, or misuse by overly broad shell tooling.
}
To generate a long-lived access token:
1. Open Home Assistant → Profile (bottom left)
2. Scroll to "Long-Lived Access Tokens"
3. Click "Create Token"
The notes confirm all calls use a long-lived access token, reinforcing that the skill depends on durable bearer credentials for authenticated control. In the context of shell-capable automation against a home-control system, long-lived tokens are especially dangerous because compromise enables persistent unauthorized actions without interactive reauthentication.
## Notes
- HA URL: `http://192.168.2.82:8123` (from MEMORY.md)
- All calls use long-lived access token (no OAuth refresh needed)
- Climate mode mappings: `cool`, `heat`, `auto`, `off`, `heat_cool`
- Temperature unit follows HA configuration (°F for US)
The README instructs users to store a long-lived Home Assistant token in a local credentials file but does not warn about the sensitivity or persistence of that secret. Because the token can grant broad API control over a Home Assistant instance, omission of handling and storage cautions increases the chance of credential exposure through weak file permissions, backups, or accidental disclosure.
The README explicitly tells users to create a long-lived token and persist it in a local credentials file, which establishes durable authentication material that may remain valid for extended periods. If the host is compromised or the file is exposed, an attacker could gain persistent API access to the Home Assistant environment and continue issuing commands until the token is revoked.
## Setup
1. Generate a long-lived access token in Home Assistant:
- Profile (bottom left) → Long-Lived Access Tokens → Create Token
- Name it "clawd" or similar
2. Create credentials file at `~/.openclaw/credentials/homeassistant.json`:
The README demonstrates commands that directly change the state of physical or environmental devices such as lights, switches, and climate controls, but it does not warn that these actions affect real-world systems. Users may run examples without appreciating the operational or safety consequences, especially for remote Home Assistant deployments controlling sensitive devices.
The skill documents shell-based execution (bash scripts/..., curl, jq) but does not declare tool scope or permissions. This weakens containment and reviewability because the skill can invoke shell capabilities without an explicit manifest-level boundary, increasing the chance of unintended command execution or overbroad agent access.
The manifest frames the skill as limited to lights, climate, switches, and sensors, but the documentation exposes a generic ability to call any Home Assistant service. That is a meaningful scope expansion because Home Assistant services can affect many domains, enabling actions well beyond the user-expected automation surface.
The invocation description is broad enough that the skill may trigger on common household requests, causing it to be selected frequently for actions that affect physical devices. Overbroad triggering raises the likelihood of accidental actuation, especially in an environment with shell execution and write-capable REST operations.
The documentation omits an explicit warning that commands and entity data are sent to a Home Assistant instance over REST API using a persistent token. Users may not realize that natural-language requests can translate into authenticated network actions against their home automation system, which reduces informed consent and safe handling.
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.
## Purpose
This skill provides read and write access to your Home Assistant entities:
- **Climate**: Set temperature, HVAC mode, query current state
- **Lights**: Turn on/off, set brightness, color
- **Switches**: Toggle on/off
A documented call any HA service interface creates a broad action primitive that can be repurposed to invoke powerful or safety-sensitive Home Assistant functionality. Because the stated purpose is much narrower, users and orchestrators may underestimate the authority being granted, increasing the chance of misuse or harmful automation.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
--arg mode "$mode" \
'{"entity_id": $entity, "temperature": $temp, "hvac_mode": $mode}')
RESPONSE=$(curl -s -X POST "${URL}/api/services/climate/set_temperature" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d "$PAYLOAD")
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
--arg mode "$mode" \
'{"entity_id": $entity, "hvac_mode": $mode}')
RESPONSE=$(curl -s -X POST "${URL}/api/services/climate/set_hvac_mode" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d "$PAYLOAD")
The script reads a long-lived Home Assistant token from a local credentials file and immediately uses it in an authenticated REST call without any user-facing notice, confirmation, or scope check. In an agent-skill context, this can cause silent access to sensitive home-state data and can normalize undisclosed use of privileged credentials, especially if invoked indirectly by user prompts or other tooling.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
PAYLOAD="{\"entity_id\": \"${entity}\", \"brightness\": ${brightness}}"
RESPONSE=$(curl -s -X POST "${URL}/api/services/light/turn_on" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d "$PAYLOAD")
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
PAYLOAD="{\"entity_id\": \"${entity}\", \"brightness\": ${brightness}}"
RESPONSE=$(curl -s -X POST "${URL}/api/services/light/turn_on" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d "$PAYLOAD")
No suspicious patterns detected.