Back to skill

Security audit

Tesla Fleet API

Security checks for vulnerabilities and agentic risk

Overview

This Tesla skill is broadly coherent, but it handles vehicle-control tokens and real vehicle commands with under-scoped safeguards that users should review before installing.

Install only if you are comfortable giving the skill Tesla OAuth access, local token storage, precise location access, and command authority over a real vehicle. Before use, restrict base_url/audience to Tesla Fleet API hosts or localhost proxy, avoid HTTP endpoints, protect private-key.pem with owner-only permissions, and require explicit human confirmation before unlock, charging, climate, honk, or location workflows.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/command.py:48
Finding

OAuth bearer and partner tokens can be transmitted to arbitrary configured endpoints

Content
View full analysis
Any: headers = { "Accept": "application/json", "Authorization": f"Bearer {token}", } body = None if json_body is not None: body = json.dumps(json_body).encode("utf-8") headers["Content-Type"] = "application/json" req = urllib.request.Request(url=url, method=method, data=body, headers=headers) ctx = None if url.startswith("https://"): ctx = ssl.create_default_context(cafile=ca_cert) if ca_cert else ssl.create_default_context() try: with urllib.request.urlopen(req, context=ctx) as resp: return json.loads(resp.read().decode("utf-8")) ``` The destination is loaded directly from local configuration without scheme or hostname validation: ```python token = auth.get("access_token") audience = cfg.get("audience") or "https://fleet-api.prd.eu.vn.cloud.tesla.com" base_url = cfg.get("base_url") or audience ca_cert = cfg.get("ca_cert") ``` The configured destination is used to retrieve vehicle identifiers and send commands: ```python def fetch_vehicles(base_url: str, token: str, ca_cert: Optional[str] = None) -> List[Dict[str, Any]]: url = f"{base_url.rstrip('/')}/api/1/vehicles" data = http_json("GET", url, token, ca_cert=ca_cert) return data.get("response", []) ``` ```python def send_command( base_url: str, token: s ...[truncated 4001 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/start_proxy.sh:58
Finding

Tesla vehicle command-signing private key permissions are not enforced

Content
View full analysis
&2 echo "" >&2 echo "Place your EC private key at:" >&2 echo " ${PRIVATE_KEY}" >&2 echo "" >&2 echo "See SETUP.md for key generation instructions." >&2 exit 1 fi ``` It then supplies that key to the privileged signing proxy without checking ownership or access mode: ```bash nohup "${PROXY_BIN}" \ -key-file "${PRIVATE_KEY}" \ -tls-key "${PROXY_DIR}/tls-key.pem" \ -cert "${PROXY_DIR}/tls-cert.pem" \ -host localhost \ -port 4443 \ >> "${LOG_FILE}" 2>&1 & ``` ### Technical Analysis The Tesla EC private key is used by the signing proxy to authenticate commands for an enrolled vehicle. Unlike the generated proxy TLS key, for which the startup script applies `chmod 600`, the vehicle command-signing key receives no equivalent protection. The final permissions therefore depend on the user's `umask`, how the file was copied, and the permissions of the surrounding workspace directories. In a shared workspace or multi-user sys ...[truncated 1820 chars]
Remediation
View remediation
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • 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
  • Rogue AgentSelf-Modification, Session Persistence
Findings (25)

Tainted flow: 'req' from os.environ.get (line 170, credential/environment) → urllib.request.urlopen (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 · scripts/vehicle_data.py (reported line 179)May include surrounding context.

python
"Accept": "application/json",
        },
    )
    with urllib.request.urlopen(req, context=ssl.create_default_context()) as resp:
        payload = json.loads(resp.read().decode("utf-8"))

    new_access = payload.get("access_token")

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

Critical
Category
Data Flow
Confidence
90% confidence
Finding

The script builds an Authorization header from a bearer token and sends it to a URL derived from configuration values such as audience or base_url. If an attacker can modify the config or trick the operator into using a malicious base URL, the access token will be disclosed to an arbitrary server, enabling unauthorized API access until the token expires or is revoked.

Content

Scanner excerpt · scripts/vehicle_data.py (reported line 231)May include surrounding context.

python
ctx = ssl.create_default_context()

    try:
        with urllib.request.urlopen(req, context=ctx) as resp:
            return json.loads(resp.read().decode("utf-8"))
    except urllib.error.HTTPError as e:
        text = e.read().decode("utf-8", errors="replace") if hasattr(e, "read") else ""

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
| `start_proxy.sh` | Start the signing proxy (for vehicle commands) |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
| `stop_proxy.sh` | Stop the signing proxy |

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 · scripts/auth.py (reported line 276)May include surrounding context.

python
print(f"📜 CA Cert:       {rt.ca_cert or '(not set)'}")
    print(f"🏠 Domain:        {rt.domain or '(not set)'}")
    print()
    print(f"🎫 Access Token:  {'(set)' if rt.access_token else '(not set)'}")
    print(f"🔄 Refresh Token: {'(set)' if rt.refresh_token else '(not set)'}")
    return 0

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Confidence
85% confidence
Finding

os.system() and os exec-family calls run shell commands with the process's full privileges, enabling arbitrary command execution.

Content

Scanner excerpt · scripts/tesla_fleet.py (reported line 29)May include surrounding context.

python
def _exec(script: str, argv: list[str]) -> None:
    target = os.path.join(HERE, script)
    os.execv(sys.executable, [sys.executable, target, *argv])


def main() -> int:

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 362)May include surrounding context.

md
token = auth.get("access_token")
    if not token:
        print("No access token. Run auth.py to authenticate.", file=sys.stderr)
        return 1

    base_url = (cfg.get("base_url") or cfg.get("audience") or "https://fleet-api.prd.eu.vn.cloud.tesla.com").rstrip("/")

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 · scripts/auth.py (reported line 333)May include surrounding context.

python
token = auth.get("access_token")
    if not token:
        print("No access token. Run auth.py to authenticate.", file=sys.stderr)
        return 1

    base_url = (cfg.get("base_url") or cfg.get("audience") or "https://fleet-api.prd.eu.vn.cloud.tesla.com").rstrip("/")

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 · scripts/command.py (reported line 810)May include surrounding context.

python
token = auth.get("access_token")
    if not token:
        print("No access token. Run auth.py to authenticate.", file=sys.stderr)
        return 1

    base_url = (cfg.get("base_url") or cfg.get("audience") or "https://fleet-api.prd.eu.vn.cloud.tesla.com").rstrip("/")

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 · scripts/command.py (reported line 821)May include surrounding context.

python
token = auth.get("access_token")
    if not token:
        print("No access token. Run auth.py to authenticate.", file=sys.stderr)
        return 1

    base_url = (cfg.get("base_url") or cfg.get("audience") or "https://fleet-api.prd.eu.vn.cloud.tesla.com").rstrip("/")

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 · scripts/vehicle_data.py (reported line 155)May include surrounding context.

python
token = auth.get("access_token")
    if not token:
        print("No access token. Run auth.py to authenticate.", file=sys.stderr)
        return 1

    base_url = (cfg.get("base_url") or cfg.get("audience") or "https://fleet-api.prd.eu.vn.cloud.tesla.com").rstrip("/")

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 · scripts/vehicle_data.py (reported line 534)May include surrounding context.

python
token = auth.get("access_token")
    if not token:
        print("No access token. Run auth.py to authenticate.", file=sys.stderr)
        return 1

    base_url = (cfg.get("base_url") or cfg.get("audience") or "https://fleet-api.prd.eu.vn.cloud.tesla.com").rstrip("/")

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 · scripts/vehicles.py (reported line 99)May include surrounding context.

python
token = auth.get("access_token")
    if not token:
        print("No access token. Run auth.py to authenticate.", file=sys.stderr)
        return 1

    base_url = (cfg.get("base_url") or cfg.get("audience") or "https://fleet-api.prd.eu.vn.cloud.tesla.com").rstrip("/")

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · SETUP.md (reported line 121)May include surrounding context.

-keyout tls-key.pem -out tls-cert.pem
-days 365 -nodes -subj "/CN=localhost"

chmod 600 tls-key.pem

text

### Configure scripts to use the proxy

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill advertises capabilities that include environment access, file read/write, network, and shell execution, but it does not declare an explicit permission or allowed-tools boundary. In an agent ecosystem, this weakens least-privilege controls and can let a caller invoke high-risk operations—especially significant here because the skill handles OAuth secrets, tokens, proxy TLS material, and remote vehicle commands.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The skill documents remote commands such as lock, unlock, honk, flash, wake, charging changes, and climate actions without an explicit warning that these affect a real physical asset. Because these commands change vehicle state and can impact physical security or safety, missing warnings can lead to accidental or unauthorized real-world actions by users or autonomous agents.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The documentation explicitly supports retrieval of vehicle GPS/location data but does not present a visible privacy warning or consent reminder. Location history and current coordinates are sensitive personal data, and normalizing access without warning increases the chance of inappropriate collection, disclosure, or use by downstream agents or users.

Content

No source excerpt is available for this finding.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · scripts/start_proxy.sh (reported line 72)May include surrounding context.

sh
-keyout "${PROXY_DIR}/tls-key.pem" \
        -out "${PROXY_DIR}/tls-cert.pem" \
        -days 365 -nodes -subj "/CN=localhost" > /dev/null 2>&1
    chmod 600 "${PROXY_DIR}/tls-key.pem"
    echo "✓ Generated TLS certificates in ${PROXY_DIR}"
fi

Session Persistence

Medium
Category
Rogue Agent
Confidence
65% 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 · scripts/start_proxy.sh (reported line 90)May include surrounding context.

sh
# --- Start ---
echo "Starting tesla-http-proxy..."

nohup "${PROXY_BIN}" \
    -key-file "${PRIVATE_KEY}" \
    -tls-key "${PROXY_DIR}/tls-key.pem" \
    -cert "${PROXY_DIR}/tls-cert.pem" \

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The script offers a --location option and, by default, also includes location_data when no endpoint flags are provided. While the code labels the output as location data, it does not provide any user-facing warning that precise coordinates may reveal sensitive whereabouts or that all-data mode includes location by default.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

This code sends the Tesla client ID and refresh token to a remote OAuth endpoint, which is a safety-relevant network operation involving credentials. While the module docstring mentions cache refresh, it does not disclose the token refresh network action, and there is no print, prompt, or comment warning the user when this occurs.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The login flow hard-codes the OAuth authorization request parameter locale to en-US. This is a natural-language/locale policy issue because the skill enforces a specific locale without offering user opt-in or documenting why that locale is required.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
79% confidence
Finding

The docstring says the module is "safe to import from any of the scripts," which implies passive utility behavior. However, this module includes load_env_file, which reads credentials from disk and mutates os.environ, so the documented safety claim overstates the absence of side effects or sensitive-state interaction.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

The script defaults the OAuth locale to "en-US" via the --locale argument, which imposes a language/locale choice unless the user discovers and overrides it. This is a natural-language policy concern because the file sets a specific locale without making it opt-in or clearly justified as region-specific.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The script persists vehicle identifiers and names to a local cache via save_vehicles, which affects user data on disk. Although the top-level docstring says it will refresh local cache, it does not clearly warn at the point of execution or explain that vehicle metadata will be stored locally in vehicles.json.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.