Back to skill

Security audit

DroneMobile

Security checks for vulnerabilities and agentic risk

Overview

This skill does what it says by controlling a DroneMobile vehicle, but it can perform real-world vehicle actions with weak guardrails and ambiguous vehicle targeting.

Review before installing. Only use this with a dedicated, trusted environment; prefer a virtualenv with pinned dependencies; set DRONEMOBILE_DEVICE_KEY for the exact vehicle; and require manual confirmation before start, stop, unlock, or trunk commands.

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

Error
Location
scripts/dronemobile.py:37
Finding

Unsafe Vehicle Selection Fallback Can Execute Commands on the Wrong Vehicle

Content
View full analysis

Vulnerability Details

File Location: scripts/dronemobile.py, lines 37–48
Vulnerability Type: Unsafe fail-open resource selection
Risk Level: High

Vulnerable Code:

python
def get_vehicle(client, device_key=None):
    vehicles = client.get_vehicles()
    if not vehicles:
        print("ERROR: No vehicles found on account")
        sys.exit(1)
    if device_key:
        for v in vehicles:
            dk = str(v.info.device_key) if hasattr(v, 'info') else str(getattr(v, 'device_key', ''))
            if dk == str(device_key):
                return v
        print(f"WARNING: Device key {device_key} not found — using first vehicle")
    return vehicles[0]

Technical Analysis

The vehicle-selection function fails open when the configured DRONEMOBILE_DEVICE_KEY does not match any returned vehicle. Instead of terminating, it warns the user and returns vehicles[0]. It also automatically chooses the first vehicle whenever no device key is configured, regardless of how many vehicles exist on the account.

This is particularly dangerous because the selected object is subsequently used for safety- and security-sensitive physical commands, including engine start, engine stop, door unlock, and trunk opening. A stale or mistyped key, a change in the dependency's vehicle object structure, or a change in API ordering can result in a command targeting an unintended vehicle.

Attack Path

  1. A DroneMobile account contains multiple registered vehicles.
  2. DRONEMOBILE_DEVICE_KEY is absent, mistyped, stale, or fails to match because the dependency exposes the key through an unexpected object structure.
  3. A user or agent requests a command such as start, unlock, or trunk.
  4. get_vehicle() fails to identify the intended vehicle.
  5. The function silently returns the first vehicle from client.get_vehicles().
  6. The requested physical-control command executes against that unintend ...[truncated 636 chars]
Remediation
View remediation

Remediation Suggestions

Implement fail-closed and unambiguous vehicle selection:

  1. If an explicit device key is supplied but no exact match is found, terminate without executing any command.
  2. If no device key is supplied, automatically select a vehicle only when exactly one vehicle exists.
  3. If multiple vehicles exist, require an explicit device key or another stable unique identifier.
  4. Validate that each vehicle exposes a usable device key before command dispatch.
  5. Display and confirm the selected vehicle's non-sensitive name or identifier before safety-sensitive operations.
  6. Add tests covering absent keys, invalid keys, duplicate or missing identifiers, multiple vehicles, and changes in vehicle ordering.

A safer implementation would follow this logic:

python
def get_vehicle(client, device_key=None):
    vehicles = client.get_vehicles()
    if not vehicles:
        raise RuntimeError("No vehicles found on account")

    if device_key:
        matches = []
        for vehicle in vehicles:
            info = getattr(vehicle, "info", None)
            actual_key = getattr(info, "device_key", None)
            if actual_key is None:
                actual_key = getattr(vehicle, "device_key", None)
            if actual_key is not None and str(actual_key) == str(device_key):
                matches.append(vehicle)

        if len(matches) != 1:
            raise RuntimeError("Configured device key did not uniquely identify a vehicle")
        return matches[0]

    if len(vehicles) != 1:
        raise RuntimeError("Multiple vehicles found; DRONEMOBILE_DEVICE_KEY is required")

    return vehicles[0]

T08 · Insecure Dependencies

Warning
Location
SKILL.md:22
Finding

Unpinned Third-Party Package Is Installed into System Python

Content
View full analysis

Vulnerability Details

File Location: SKILL.md, lines 22–25
Vulnerability Type: Unsafe and non-reproducible dependency installation
Risk Level: Medium

Vulnerable Code:

markdown
Install the library if not present:
```bash
pip install drone-mobile --break-system-packages
text

### Technical Analysis

The setup instructions install the latest version resolved for `drone-mobile` and its transitive dependencies without a version pin, lock file, or package hash verification. Consequently, the code reviewed during the audit may not be the same dependency code installed later.

The `--break-system-packages` option also bypasses Python's externally managed environment protection and permits pip to modify the system-managed Python environment. Installation may execute package-controlled build or installation code and may replace versions required by other applications.

Although the project history contains no evidence that the named package is currently malicious, this installation method unnecessarily increases supply-chain exposure and weakens environment isolation.

### Attack Path

1. A user follows the installation command in `SKILL.md`.
2. Pip resolves the package and transitive dependencies at installation time from its configured package index.
3. A compromised, malicious, or unexpectedly changed future package release is selected because no reviewed version or hash is enforced.
4. Package-controlled installation or build code executes with the privileges of the user running pip.
5. The package is installed into the system Python environment because `--break-system-packages` bypasses the normal protection.
6. The Skill imports the installed package, which receives the DroneMobile email and password and performs authenticated vehicle operations.

### Impact Assessment

Installation-time code can act with the privileges of the account running pip. If the command is run as an administrator, im
...[truncated 477 chars]
Remediation
View remediation

Remediation Suggestions

  1. Create and use a dedicated virtual environment rather than modifying system Python.
  2. Pin drone-mobile to a specifically reviewed version.
  3. Lock all transitive dependencies to reproducible versions.
  4. Record and enforce cryptographic package hashes using a requirements file and pip install --require-hashes.
  5. Remove --break-system-packages from the documented installation command.
  6. Review dependency updates before changing locked versions and use automated vulnerability and provenance scanning.
  7. Run the Skill under a dedicated, least-privileged operating-system account where practical.

Example hardened installation workflow:

bash
python3 -m venv .venv
. .venv/bin/activate
python3 -m pip install --require-hashes -r requirements.txt

The corresponding requirements.txt should contain reviewed, exact versions and hashes for the direct package and every transitive dependency.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (5)

Missing User Warnings

High
Category
Not specified by scanner
Confidence
93% confidence
Finding

This skill can remotely start or stop a vehicle, unlock doors, and open the trunk without any explicit confirmation, warning, or additional authorization step at the point of action. In an agent setting, mistaken invocation, prompt confusion, or unauthorized access to the agent could trigger real-world safety and security consequences, including theft facilitation or unsafe vehicle operation.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill requires sensitive environment credentials and performs privileged vehicle-control actions, but it does not declare any explicit tool scope or permissions boundary. That omission can allow broader-than-expected access patterns and makes it harder for a host platform to enforce least privilege for secrets and command execution.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

This skill enables safety-critical remote actions such as starting a vehicle, unlocking doors, and opening the trunk, yet the description provides no explicit warning, confirmation requirement, or misuse caveat. In context, these are real-world physical actions affecting property and potentially personal safety, so absent warnings and guardrails increase the risk of accidental or unauthorized activation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

This code reads DRONEMOBILE_EMAIL and DRONEMOBILE_PASSWORD from environment variables to authenticate against a vehicle-control service. Although it errors if they are missing, there is no comment, docstring warning, or user-facing disclosure that the skill accesses sensitive credentials from the environment.

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

python
print(f"   Engine: {engine} | Doors: {locked} | Battery: {batt}V | Temp: {temp}°C")
            print(f"   Door: {door} | Hood: {hood} | Mileage: {mileage} mi")
        else:
            method = getattr(vehicle, cmd)
            response = method()
            success = parse_success(response)
            temp, batt, engine = get_telemetry(response.raw_data)

Static analysis

No suspicious patterns detected.