Back to skill

Security audit

Shelly Sync

Security checks for vulnerabilities and agentic risk

Overview

This skill has a coherent home-energy automation purpose, but it under-discloses Home Assistant credential use and can change appliance state without clear safety controls.

Review this skill carefully before installing. Use only a dedicated, minimally privileged Home Assistant token, point HOME_ASSISTANT_URL only at a trusted local Home Assistant instance, prefer HTTPS or a trusted private network, and avoid using target_load unless you are comfortable with the skill turning on mapped appliances automatically when it detects surplus power.

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

T09 · Insecure Skill Coding Practices

Error
Location
shelly_client.py:10
Finding

Home Assistant bearer token transmitted to an unvalidated endpoint without mandatory TLS

Content
View full analysis

Vulnerability Details

File Location: shelly_client.py, lines 10–11, 41–65, and 97–109
Vulnerability Type: Sensitive credential exposure through an unvalidated network destination and insecure transport
Risk Level: High

Vulnerable Code

python
HA_URL = os.getenv("HOME_ASSISTANT_URL")
HA_TOKEN = os.getenv("SUPER_SECRET_HA_TOKEN")
python
def trigger_home_assistant(entity_id: str, state: str) -> dict:
    """Toggle a Home Assistant entity."""
    if not HA_URL or not HA_TOKEN:
        return {"status": "error", "message": "Home Assistant credentials not configured"}

    headers = {
        "Authorization": f"Bearer {HA_TOKEN}",
        "Content-Type": "application/json"
    }
    service = "homeassistant.turn_on" if state == "on" else "homeassistant.turn_off"
    domain = entity_id.split(".")[0]

    try:
        response = requests.post(
            f"{HA_URL}/api/services/{service}",
            headers=headers,
            json={"entity_id": entity_id},
            timeout=10
        )
        response.raise_for_status()
        return {"status": "success", "action": f"{domain} turned {state}"}
    except Exception as e:
        return {"status": "error", "message": str(e)}
python
if metrics["surplus"]:
    result = {
        **metrics,
        "action_taken": f"Surplus of {surplus_w}W available. Load optimization possible."
    }

    # Auto-trigger target if specified
    if target_load:
        load_map = {
            "heatpump": "switch.heatpump",
            "charger": "switch.ev_charger",
            "dishwasher": "switch.dishwasher",
            "washing": "switch.washing_machine"
        }
        entity_id = load_map.get(target_load.lower())
        if entity_id:
            trigger_result = trigger_home_assistant(entity_id, "on")
            result["homeassistant"] = trigger_result

Technical Analysis

...[truncated 2945 chars]

Remediation
View remediation

Remediation Suggestions

  1. Parse HOME_ASSISTANT_URL with urllib.parse.urlparse and reject malformed URLs.
  2. Require https for authenticated requests. If a local installation cannot support TLS, explicitly restrict it to an approved private address and document the remaining interception risk.
  3. Allowlist the exact expected Home Assistant hostname or IP address and permitted port instead of accepting an arbitrary destination.
  4. Reject URLs containing user information, query strings, fragments, or unexpected paths.
  5. Disable automatic redirects for authenticated requests, or independently validate every redirect destination before forwarding credentials.
  6. Use a dedicated, minimally privileged Home Assistant account and token limited to the entities and services required for load optimization.
  7. Store the token in an approved secret-management facility and rotate it immediately if exposure is suspected.
  8. Add HOME_ASSISTANT_URL and the required secret to SKILL.md, clearly documenting why they are needed and that an authenticated network request is performed.
  9. Consider requiring explicit confirmation or a configured power threshold before appliance activation, rather than activating a target whenever any negative total power is observed.
  10. Avoid returning raw exception text to callers where it could disclose internal endpoint or networking details; log sanitized diagnostic information separately.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (5)

Tainted flow: 'headers' from os.getenv (line 49, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · shelly_client.py (reported line 57)May include surrounding context.

python
domain = entity_id.split(".")[0]

    try:
        response = requests.post(
            f"{HA_URL}/api/services/{service}",
            headers=headers,
            json={"entity_id": entity_id},

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill declares capabilities that imply environment-variable access and network communication, but it does not define an explicit tool scope such as permissions or allowed-tools. That creates an avoidable trust gap: an agent or reviewer cannot easily verify what external access is intended, which increases the risk of overbroad execution or misuse of local network connectivity and sensitive configuration like SHELLY_EM_IP.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The skill explicitly states it can trigger smart plugs or appliances and perform load optimization, but it does not warn the user that invoking it may change physical device state. In a home automation context, silent state changes can unexpectedly start or stop appliances, causing safety, equipment, or operational issues, especially for loads like heat pumps or chargers.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · shelly_client.py (reported line 57)May include surrounding context.

python
domain = entity_id.split(".")[0]

    try:
        response = requests.post(
            f"{HA_URL}/api/services/{service}",
            headers=headers,
            json={"entity_id": entity_id},

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill can automatically turn on mapped Home Assistant entities when surplus power is detected, without confirmation, policy checks, or safety interlocks. In a home-automation context, unauthorized or mistaken activation of appliances can cause safety issues, equipment wear, unwanted energy use, or operational disruption, especially if the trigger input is inaccurate or abused.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.