Back to skill

Security audit

Homebridge

Security checks for vulnerabilities and agentic risk

Overview

The skill appears purpose-aligned, but it deserves review because it can use stored smart-home credentials to immediately change physical device state and does not enforce HTTPS.

Review before installing. Use this only with a trusted Homebridge instance, configure an https:// URL, prefer a least-privileged Homebridge account, protect the credential file, and understand that set commands can immediately change real devices such as switches, fans, and thermostats.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/homebridge_api.py:50
Finding
Homebridge credentials and bearer tokens may be transmitted over unencrypted HTTP<![CDATA[ ## Vulnerability Details **File Location**: `scripts/homebridge_api.py:50-78` and `scripts/homebridge_api.py:174-181` **Vulnerability Type**: Missing HTTPS enforcement for sensitive authentication traffic **Risk Level**: High ### Vulnerable Code ```python def make_request(url: str, method: str = "GET", data: dict = None, token: str = None) -> dict: """Make HTTP request to Homebridge API.""" headers = {"Content-Type": "application/json"} if token: headers["Authorization"] = f"Bearer {token}" body = json.dumps(data).encode() if data else None req = Request(url, data=body, headers=headers, method=method) try: with urlopen(req, timeout=30) as resp: return json.loads(resp.read().decode()) except HTTPError as e: error_body = e.read().decode() if e.fp else "" print(f"HTTP Error {e.code}: {e.reason}", file=sys.stderr) if error_body: print(f"Response: {error_body}", file=sys.stderr) sys.exit(1) except URLError as e: print(f"Connection error: {e.reason}", file=sys.stderr) sys.exit(1) def authenticate(base_url: str, username: str, password: str) -> str: """Authenticate and return access token.""" url = f"{base_url}/api/auth/login" data = {"username": username, "password": password} response = make_request(url, method="POST", data=data) return response.get("access_token") ``` The configured URL is used without validating its scheme: ```python config = load_config() base_url = config["url"].rstrip("/") username = config["username"] password = config["password"] # Authenticate token = authenticate(base_url, username, password) ``` ### Technical Analysis The script reads an administrative username and password from `~/.clawdbot/credentials/homebridge.json` and sends them to the configured Homebridge URL. After authentication, it sends the returned bearer token in the `Authorization` header on subsequent API requests. ...[truncated 2564 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. **Require HTTPS before loading or transmitting credentials.** Parse and validate the configured URL before authentication: ```python from urllib.parse import urlsplit def validate_base_url(raw_url: str) -> str: url = raw_url.rstrip("/") parsed = urlsplit(url) if parsed.scheme.lower() != "https": raise ValueError("Homebridge URL must use HTTPS") if not parsed.hostname: raise ValueError("Homebridge URL must include a valid hostname") if parsed.username or parsed.password: raise ValueError("Credentials must not be embedded in the URL") return url ``` Apply it when reading the configuration: ```python try: base_url = validate_base_url(config["url"]) except ValueError as e: print(f"Error: {e}", file=sys.stderr) sys.exit(1) ``` 2. **Do not silently fall back to HTTP.** If plaintext access is required for a narrowly defined loopback-only deployment, require an explicit insecure opt-in and restrict it to verified loopback addresses. Display a prominent warning. Plaintext access to LAN or remote hosts should remain prohibited. 3. **Preserve TLS certificate verification.** Do not use an unverified SSL context. For local deployments using a private or self-signed certificate, support a configurable trusted CA certificate instead of disabling verification. 4. **Use a least-privileged Homebridge account.** The configured account should have only the API permissions required to enumerate and control intended accessories, where supported. 5. **Protect the credential file.** Require or warn when `~/.clawdbot/credentials/homebridge.json` is readable by group or other users. Recommended permissions are `0600`, with the parent credentials directory restricted to the owning user. 6. **Limit sensitive error output.** Avoid printing arbitrary authentication response bodies because a server or intermediary could retu ...[truncated 257 chars]
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
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (7)

Credential Access

High
Category
Privilege Escalation
Content
def authenticate(base_url: str, username: str, password: str) -> str:
    """Authenticate and return access token."""
    url = f"{base_url}/api/auth/login"
    data = {"username": username, "password": password}
    response = make_request(url, method="POST", data=data)
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill performs network operations against a Homebridge REST API but does not declare any explicit tool scope or allowed-tools metadata. This weakens runtime policy enforcement and transparency, making it easier for a skill capable of changing physical device state to be invoked without clear permission boundaries.

External Transmission

Medium
Category
Data Exfiltration
Content
```bash
# Get auth token
TOKEN=$(curl -s -X POST "${HOMEBRIDGE_URL}/api/auth/login" \
  -H "Content-Type: application/json" \
  -d "{\"username\":\"${HOMEBRIDGE_USERNAME}\",\"password\":\"${HOMEBRIDGE_PASSWORD}\"}" \
  | jq -r '.access_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.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The skill describes commands that can turn devices on or off and modify thermostat or fan settings, but it does not warn users that these actions affect the physical environment and may create safety, comfort, or energy risks. In a home automation context, silent device-control capability is more dangerous because users may not appreciate that routine-looking API calls can unlock hazardous real-world outcomes.

External Transmission

Medium
Category
Data Exfiltration
Content
```bash
# Turn on a light/switch
curl -s -X PUT "${HOMEBRIDGE_URL}/api/accessories/{uniqueId}" \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{"characteristicType": "On", "value": true}'
Confidence
60% 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
95% confidence
Finding
This code exposes a `set` operation that sends a PUT request to change an accessory characteristic, which can directly alter device state in the user's environment. There is no confirmation prompt, cautionary print/log message, or other user-facing disclosure before executing the change.

Intent-Code Divergence

Low
Confidence
98% confidence
Finding
The module docstring says credentials are read from `~/.clawdbot/clawdbot.json` under `skills.entries.homebridge`, but `load_config()` actually reads `~/.clawdbot/credentials/homebridge.json`. This is an active contradiction between the documented setup and the implemented behavior, which can mislead operators about where sensitive credentials are sourced from.

Static analysis

No suspicious patterns detected.