Back to skill

Security audit

Emporia Energy

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its stated energy-query purpose, but it includes an undocumented cloud-login path that can connect to an arbitrary host while the skill handles sensitive Emporia and ESPHome credentials.

Review this before installing. Use only trusted configuration values, avoid any EMPORIA_EMAIL value beginning with vue_simulator@ unless you intentionally need simulator behavior, and run the skill in an isolated virtual environment with only the Emporia or ESPHome secrets it needs. Consider pinning the ESPHome dependency before use.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/emporia_cloud.py:47
Finding

Undocumented Arbitrary-Host Simulator Connection

Content
View full analysis

Vulnerability Details

File Location: scripts/emporia_cloud.py, lines 47–51
Vulnerability Type: Arbitrary outbound network connection / insufficient destination validation
Risk Level: Medium

python
def login(vue, email, password):
    if email.startswith("vue_simulator@"):
        host = email.split("@", 1)[1]
        return vue.login_simulator(host)
    return vue.login(email, password)

Technical Analysis

The cloud login function interprets an EMPORIA_EMAIL value beginning with vue_simulator@ as a request to connect to a simulator at the hostname following the @ character. The destination is passed to PyEmVue.login_simulator() without validation or an allowlist.

This simulator behavior is not documented in SKILL.md and is not required for the declared functionality of querying the Emporia cloud service. It therefore expands the Skill's network reach beyond the minimum destination scope needed for normal cloud mode. Depending on the behavior of the installed PyEmVue implementation, this can provide an SSRF-like network reachability primitive.

The reviewed code does not pass EMPORIA_PASSWORD to login_simulator(). Consequently, the available evidence does not establish password exfiltration through this path.

Attack Path

  1. An attacker or untrusted configuration source controls the Skill's EMPORIA_EMAIL environment variable.
  2. The attacker sets it to a value such as vue_simulator@attacker-controlled.example or a hostname resolving to an internal service.
  3. The user or agent invokes any cloud command, such as summary.
  4. login() extracts the attacker-selected hostname.
  5. vue.login_simulator(host) initiates a network connection to that destination.
  6. The destination can observe the connection, or the behavior can be used to attempt access to hosts reachable from the Skill's execution environment.

Impact Assessment

Exploitation permits attacker-dire ...[truncated 356 chars]

Remediation
View remediation

Remediation Suggestions

  1. Remove simulator support from the production Skill if it is not required by the declared functionality.
  2. If simulator support is necessary, expose it through an explicit mode such as EMPORIA_MODE=simulator rather than overloading the email field.
  3. Restrict simulator destinations to a strict allowlist or, for development-only use, loopback addresses.
  4. Resolve hostnames and reject private, link-local, loopback, multicast, and metadata-service addresses unless a narrowly defined use case explicitly requires them.
  5. Apply connection timeouts and avoid following destination redirects.
  6. Document the simulator mode, its network behavior, and its trust assumptions.
  7. Keep cloud mode restricted to the expected Emporia service endpoints.

T08 · Insecure Dependencies

Note
Location
requirements-esphome.txt:1
Finding

Unbounded ESPHome Dependency Version

Content
View full analysis

Vulnerability Details

File Location: requirements-esphome.txt, line 1
Vulnerability Type: Non-reproducible dependency resolution / supply-chain exposure
Risk Level: Low

text
aioesphomeapi>=18.0.0

The associated installation instruction in SKILL.md, lines 91–94, is:

text
ESPHome:
text
python3 -m venv .venv
source .venv/bin/activate
pip install -r {baseDir}/requirements-esphome.txt

Technical Analysis

The lower-bound-only requirement allows pip to install any current or future release of aioesphomeapi that satisfies >=18.0.0, along with dependency versions selected at installation time. As a result, installations are not reproducible and may execute package code that was never reviewed with this Skill.

This is security-relevant because the dependency is instantiated by scripts/emporia_esphome.py in a process that receives an ESPHome password or Noise PSK and has local network access. No evidence was found that the currently named package is malicious; the issue is the lack of version and artifact integrity controls.

Attack Path

  1. A user follows the documented ESPHome installation instructions.
  2. pip resolves aioesphomeapi>=18.0.0 at installation time.
  3. A newer, compromised, or unexpectedly incompatible release satisfies the requirement.
  4. The selected package is installed without project-level review or hash verification.
  5. When the ESPHome script imports and uses the package, its code executes with the permissions, environment access, and network access of the Skill process.

Impact Assessment

A compromised dependency could potentially access environment variables, including ESPHOME_API_KEY or ESPHOME_PASSWORD, read files available to the executing user, or communicate over the network. The exact impact would depend on the behavior of a future dependency release and the privileges assigned to the Skill process. The repository itsel ...[truncated 53 chars]

Remediation
View remediation

Remediation Suggestions

  1. Pin aioesphomeapi to an exact version that has been tested and reviewed.
  2. Generate a lockfile that also fixes transitive dependency versions.
  3. Use package hashes, such as pip's --require-hashes, to verify downloaded artifacts.
  4. Review dependency updates before changing the pinned version.
  5. Use automated vulnerability and provenance checks as part of the update process.
  6. Install and run the Skill in an isolated virtual environment under a minimally privileged account.
  7. Limit the process's filesystem and network access to the resources required for querying the configured ESPHome device.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (7)

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
80% confidence
Finding

Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Content

Scanner excerpt · scripts/common.py (reported line 67)May include surrounding context.

python
for ch in channels:
        name = normalize(ch.get("name"))
        channel_num = normalize(ch.get("channel_num"))
        if any(token in name for token in ["total", "mains", "main", "usage"]):
            preferred.append(ch)
        elif channel_num in ("1,2,3", "1,2"):
            preferred.append(ch)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding

The skill declares required environment variables, including sensitive credentials such as EMPORIA_EMAIL, EMPORIA_PASSWORD, and optional API keys, but does not define an explicit tool scope or permissions boundary. That omission can allow an agent runtime to expose or use environment-backed secrets more broadly than intended, increasing the risk of unintended credential access or use by other skill logic.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

This markdown file describes cloud credentials and a local API key, and the example later includes environment variables for an email, password, and ESPHome API key. Under the markdown-specific warning rule, the description should disclose that the skill uses sensitive credentials and may affect user privacy or system security if misconfigured.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The script reads Emporia account credentials from environment variables and then logs in and fetches device and usage data from the cloud service. There is no confirmation prompt, user-facing print/log message, or inline comment/docstring warning that the skill will transmit credentials and retrieve potentially sensitive household energy telemetry over the network.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
94% confidence
Finding

The dependency is specified with a lower bound only ("aioesphomeapi>=18.0.0"), which allows installation of any newer version, including future releases that may introduce breaking changes, insecure transitive dependencies, or a compromised upstream package version. In a skill that interfaces with local ESPHome devices, this weakens supply-chain reproducibility and makes builds less predictable, though it is not by itself evidence of malicious behavior.

Content

Scanner excerpt · requirements-esphome.txt (reported line 1)May include surrounding context.

text
aioesphomeapi>=18.0.0

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
87% confidence
Finding

The helper reads environment variables and can terminate execution if a required variable is missing, but there is no docstring, comment, or user-facing notice explaining that the skill accesses environment configuration. For code files, access to sensitive environment variables should have some visible disclosure unless clearly documented elsewhere, which is not present in this file.

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/emporia_esphome.py (reported line 47)May include surrounding context.

python
def state_value(state):
    for attr in ("state", "value", "text"):
        if hasattr(state, attr):
            return getattr(state, attr)
    return None

Static analysis

No suspicious patterns detected.