Back to skill

Security audit

Tesla Commands

Security checks for vulnerabilities and agentic risk

Overview

This skill mostly does what it says, but it can change a real vehicle's state and includes an undocumented command that deletes charging schedules without confirmation.

Review this carefully before installing. Only use it with a MyTeslaMate token you are comfortable granting vehicle-control authority to, avoid letting agents run state-changing commands automatically, and treat schedule deletion, charge-limit changes, climate control, and wake actions as requiring explicit user confirmation.

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
bin/tesla-control.py:52
Finding
Undocumented Destructive Charge-Schedule Removal Command<![CDATA[ ## Vulnerability Details **File Location**: `bin/tesla-control.py`, lines 52 and 80-82 **Vulnerability Type**: Undocumented destructive vehicle-control operation **Risk Level**: Medium ### Technical Analysis The command-line interface defines and implements `--remove-schedules`, which permanently removes all charging schedules associated with the selected vehicle: ```python parser.add_argument("--remove-schedules", action="store_true", help="Completely remove all charge schedules") ``` The corresponding command handler sends an authenticated request to the MyTeslaMate API: ```python elif args.remove_schedules: # According to Tesla Fleet API, remove_charge_schedule completely deletes the configuration print(json.dumps(call_api("command/remove_charge_schedule", method="POST", data={}, vin=args.vin))) ``` This operation is not listed among the supported options in `SKILL.md`. The documented `--clear-schedule` operation only disables scheduled charging, whereas this hidden option completely deletes the schedule configuration. Because the tool is intended for use by an AI agent, exposing an undocumented destructive capability increases the likelihood that the command will be invoked without the user understanding that it differs materially from merely disabling a schedule. The operation also lacks a confirmation mechanism, dry-run mode, or other safeguard. ### Attack Path 1. An attacker, automated agent, or user with access to the skill execution interface discovers the `--remove-schedules` argument from the source code or command help. 2. The process runs with a valid `TESLA_MATE_TOKEN` and a target VIN supplied through `--vin` or `TESLA_VIN`. 3. The following command is invoked: ```bash ./bin/tesla-control.py --remove-schedules ``` 4. The tool sends an authenticated POST request to the `command/remove_charge_schedule` API endpoint. 5. The selected vehicle's charging-schedule configuration is removed without an additional confi ...[truncated 518 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `--remove-schedules` if permanent schedule deletion is not an intended public capability. 2. If the operation is required, document it clearly in `SKILL.md`, including the distinction between disabling and deleting schedules. 3. Require explicit confirmation before issuing the destructive request, such as: ```bash ./bin/tesla-control.py --remove-schedules --confirm-remove-schedules ``` 4. Return an error when the confirmation flag is absent. 5. Consider providing a dry-run mode that reports the target vehicle and intended operation without sending the request. 6. Log a non-sensitive audit event recording the operation and target VIN while ensuring that the API token is never logged. 7. Where supported by the service, use an API token scoped only to the minimum vehicle-control operations required by the skill. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
bin/tesla-control.py:50
Finding
Missing Range Validation for Safety-Relevant Vehicle Configuration<![CDATA[ ## Vulnerability Details **File Location**: `bin/tesla-control.py`, lines 50-51 and 70-78 **Vulnerability Type**: Insufficient input validation **Risk Level**: Low ### Technical Analysis The command-line help states that the charge limit must be between 50 and 100, but the implementation accepts any integer: ```python parser.add_argument("--climate", choices=["on", "off"], help="Turn climate on or off") parser.add_argument("--charge-limit", type=int, help="Set charge limit (50-100)") ``` The value is forwarded directly to the remote vehicle-control API without enforcing the documented range: ```python elif args.charge_limit: print(json.dumps(call_api("command/set_charge_limit", method="POST", data={"percent": args.charge_limit}, vin=args.vin))) ``` The truthiness check also handles zero inconsistently: `--charge-limit 0` is parsed successfully but causes the branch to be skipped rather than producing a validation error. Scheduled charging has a similar validation weakness: ```python elif args.set_schedule: try: h, m = map(int, args.set_schedule.split(":")) minutes = h * 60 + m payload = {"enable": True, "time": minutes} print(json.dumps(call_api("command/set_scheduled_charging", method="POST", data=payload, vin=args.vin))) except ValueError: print(json.dumps({"error": "Invalid time format. Use HH:MM"})) ``` The code validates only that two integer-like components can be parsed. It does not ensure that the hour is between 0 and 23 or that the minute is between 0 and 59. Inputs such as `99:99` therefore produce an out-of-range value and are sent to the API. The remote API may reject invalid values, but relying exclusively on server-side validation is unsafe for a vehicle-control client. If the upstream service normalizes or accepts unexpected values, the resulting vehicle configuration may differ from the user's intent. ### Attack Path 1. An attacker, user, or automated agent can invoke the ...[truncated 1066 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Check charge-limit presence explicitly rather than using truthiness: ```python elif args.charge_limit is not None: ``` 2. Reject charge limits outside the documented range before calling the API: ```python if not 50 <= args.charge_limit <= 100: print(json.dumps({"error": "Charge limit must be between 50 and 100."})) sys.exit(2) ``` 3. Enforce valid 24-hour time ranges: ```python h, m = map(int, args.set_schedule.split(":")) if not 0 <= h <= 23 or not 0 <= m <= 59: raise ValueError ``` 4. Require exactly one colon-separated hour and minute component and reject extra components or surrounding ambiguity. 5. Exit with a nonzero status after validation errors so callers can reliably detect failure. 6. Add automated tests covering boundary values, including charge limits of 49, 50, 100, and 101, and times such as `00:00`, `23:59`, `24:00`, and `12:60`. 7. Retain server-side validation as defense in depth rather than treating it as a substitute for client-side validation. ]]>
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 (7)

Tainted flow: 'req' from os.environ.get (line 28, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Content
req = urllib.request.Request(url, headers=headers, method=method)
        if data is not None:
            body = json.dumps(data).encode('utf-8')
            with urllib.request.urlopen(req, data=body) as response:
                return json.loads(response.read().decode())
        else:
            with urllib.request.urlopen(req) as response:
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Tainted flow: 'req' from os.environ.get (line 28, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Content
with urllib.request.urlopen(req, data=body) as response:
                return json.loads(response.read().decode())
        else:
            with urllib.request.urlopen(req) as response:
                return json.loads(response.read().decode())
    except urllib.error.HTTPError as e:
        try:
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Lp3

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding
The skill declares no explicit tool scope even though its documented behavior depends on environment variables and network access. In a skill that can remotely control a real vehicle, missing permission boundaries increases the chance of unintended capability exposure, confused-deputy behavior, or use in contexts where operators do not realize the skill can access secrets and perform outbound control actions.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The documentation advertises remote vehicle-control operations such as wake, climate changes, and charging schedule updates without any safety warnings, confirmation guidance, or mention of real-world consequences. Because these actions affect a physical asset, omission of operational safety context can lead to accidental activation, misuse by an uninformed operator, or automation that changes vehicle state at inappropriate times.

External Transmission

Medium
Category
Data Exfiltration
Content
# Configuration should come from Environment Variables
TOKEN = os.environ.get("TESLA_MATE_TOKEN")
DEFAULT_VIN = os.environ.get("TESLA_VIN")
API_BASE = "https://api.myteslamate.com/api/1/vehicles"

def call_api(path, method="GET", data=None, vin=None):
    if not TOKEN:
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
req = urllib.request.Request(url, headers=headers, method=method)
        if data is not None:
            body = json.dumps(data).encode('utf-8')
            with urllib.request.urlopen(req, data=body) as response:
                return json.loads(response.read().decode())
        else:
            with urllib.request.urlopen(req) as response:
Confidence
70% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The script exposes state-changing vehicle commands such as wake, climate control, charge-limit changes, and schedule removal without any confirmation, dry-run mode, or user-facing warning. In an agent skill context, this increases the risk of accidental or prompt-induced execution that can directly alter vehicle behavior, making the operational context more dangerous than a typical local CLI utility.

Static analysis

No suspicious patterns detected.