Back to skill

Security audit

ESP32-CAM Eyes

Security checks for vulnerabilities and agentic risk

Overview

The skill is documentation-only and aligned with setting up ESP32 cameras, but it guides users to expose live camera images without authentication and with a predictable fallback Wi-Fi access point.

Install only if you are prepared to secure the device yourself. Use a dedicated IoT or isolated network, do not port-forward the camera, remove wildcard CORS unless needed, add authentication or restrict access to trusted clients, replace the fallback AP credentials with a unique strong secret or disable AP fallback, and avoid storing real Wi-Fi credentials in shared source code.

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

T09 · Insecure Skill Coding Practices

Error
Location
references/setup-guide.md:231
Finding
Unauthenticated Plaintext Access to Camera Images and Live Streams<![CDATA[ ## Vulnerability Details **File Location**: `references/setup-guide.md`, lines 231–235 **Vulnerability Type**: Missing authentication and transport security **Risk Level**: High ### Vulnerable Code ```cpp config.server_port = 80; if (httpd_start(&camera_httpd, &config) == ESP_OK) { httpd_uri_t u1 = { .uri = "/", .method = HTTP_GET, .handler = index_handler }; httpd_uri_t u2 = { .uri = "/capture", .method = HTTP_GET, .handler = capture_handler }; httpd_uri_t u3 = { .uri = "/stream", .method = HTTP_GET, .handler = stream_handler }; ``` ### Technical Analysis The generated firmware exposes the web interface, individual camera snapshots, and the live MJPEG stream over port 80 without any authentication or authorization checks. Requests are accepted solely based on network reachability. Because the service uses plaintext HTTP, camera content can also be observed or modified by an attacker with a suitable position on the network. The implementation does not require a password, API token, signed request, client certificate, or trusted source address before invoking the camera handlers. ### Attack Path 1. The victim flashes the documented firmware and connects the camera to a Wi-Fi or fallback access-point network. 2. An attacker obtains network reachability to the ESP32 device. 3. The attacker discovers the device through network scanning, DHCP information, mDNS, serial-output disclosure, or a known fixed address. 4. The attacker requests `http://<camera-ip>/capture` to retrieve snapshots or `http://<camera-ip>/stream` to receive a live video stream. 5. The server returns camera imagery without requesting credentials. 6. If the attacker can monitor local traffic, plaintext imagery may also be passively intercepted. ### Impact Assessment Any network-reachable attacker can obtain camera snapshots and continuous video. This can result in unauthorized surveillance and disclosure of people, physical locations, documents, screens, possessions, ...[truncated 234 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Require authentication for `/`, `/capture`, and `/stream`, using a strong device-specific secret or short-lived signed tokens. - Reject requests before acquiring a camera frame unless authorization succeeds. - Do not expose the camera directly to untrusted networks. - Place the device on a dedicated VLAN or isolated IoT network and restrict access with firewall rules. - Use a trusted TLS-terminating reverse proxy or gateway if HTTPS cannot be implemented safely on the device. - Avoid router port forwarding and Universal Plug and Play exposure. - Add request throttling and authentication-failure logging where device resources permit. - Document secure credential provisioning and rotation procedures. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
references/setup-guide.md:162
Finding
Wildcard CORS Policy Permits Cross-Origin Retrieval of Camera Snapshots<![CDATA[ ## Vulnerability Details **File Location**: `references/setup-guide.md`, lines 162 and 174 **Vulnerability Type**: Overly permissive cross-origin resource sharing **Risk Level**: Medium ### Vulnerable Code ```cpp if (fb->format == PIXFORMAT_JPEG) { httpd_resp_set_type(req, "image/jpeg"); httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); esp_err_t res = httpd_resp_send(req, (const char *)fb->buf, fb->len); ``` ```cpp if (ok) { httpd_resp_set_type(req, "image/jpeg"); httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); esp_err_t res = httpd_resp_send(req, (const char *)jpg_buf, jpg_len); ``` ### Technical Analysis Both successful paths in the snapshot handler return `Access-Control-Allow-Origin: *`. This permits JavaScript executing under any web origin to read snapshot responses when the browser can reach the ESP32. The policy is especially dangerous when combined with the absence of endpoint authentication. A malicious website can attempt requests to common private-network addresses and, where browser private-network controls do not prevent the request, read camera images directly. ### Attack Path 1. The victim's browser is connected to a network from which the ESP32 camera is reachable. 2. The victim visits an attacker-controlled website. 3. JavaScript on that website probes a known, guessed, or previously discovered camera address. 4. The script requests `http://<camera-ip>/capture`. 5. The ESP32 returns the image with `Access-Control-Allow-Origin: *`. 6. The browser allows the attacker's JavaScript to read and transmit the image, subject to the browser's applicable mixed-content and private-network access restrictions. ### Impact Assessment A hostile website may retrieve and exfiltrate snapshots through a victim's browser without requiring direct attacker membership in the local network. The practical scope depends on browser network protections and knowledge of the device address, but successful ...[truncated 141 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Remove the `Access-Control-Allow-Origin` header unless browser-based cross-origin access is strictly required. - If CORS is necessary, compare the request origin against a small, explicit allowlist and return only the matching trusted origin. - Do not dynamically reflect arbitrary `Origin` values. - Require authentication independently of CORS; CORS is not an access-control mechanism. - Consider serving the user interface and API from the same origin to eliminate the cross-origin requirement. - Apply suitable `Content-Security-Policy`, `X-Content-Type-Options`, and anti-caching headers where supported. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
references/setup-guide.md:304
Finding
Fallback Access Point Uses a Globally Predictable Password<![CDATA[ ## Vulnerability Details **File Location**: `references/setup-guide.md`, lines 304–309 **Vulnerability Type**: Hardcoded weak network credential **Risk Level**: High ### Vulnerable Code ```cpp } else { Serial.println("\nWiFi connection failed! Starting AP mode..."); WiFi.softAP("ESP32-CAM", "12345678"); startCameraServer(); Serial.printf("AP mode: http://%s/capture\n", WiFi.softAPIP().toString().c_str()); } ``` ### Technical Analysis When the station-mode Wi-Fi connection fails, the firmware automatically creates an access point named `ESP32-CAM` with the fixed password `12345678`. This password is globally predictable and identical for every deployment following the guide. The code immediately starts the unauthenticated camera server on that access point. Therefore, knowledge of the documented password is sufficient for a nearby attacker to join the network and access live imagery. The fallback can occur because of routine events such as a changed router password, unavailable access point, temporary radio interference, or incorrect credentials. ### Attack Path 1. The ESP32 fails to connect to its configured Wi-Fi network. 2. The device automatically starts the `ESP32-CAM` fallback access point. 3. A nearby attacker identifies the access point through a wireless scan. 4. The attacker connects using the documented password `12345678`. 5. The attacker determines the ESP32 access-point address, normally available as the network gateway. 6. The attacker opens `/capture` or `/stream`. 7. Because the HTTP service has no application-level authentication, the attacker receives camera imagery. ### Impact Assessment Any attacker within Wi-Fi range can potentially join the fallback network and access snapshots or continuous camera video. The exposure may remain active indefinitely because the fallback mode has no timeout. The attacker gains network access to the ESP32 access point and access to every unauthenticated service hosted by th ...[truncated 113 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Generate a cryptographically random, unique access-point password for each device. - Communicate the initial secret through a controlled out-of-band method, such as a device label, QR code, or trusted serial provisioning session. - Require explicit physical activation before entering provisioning mode. - Disable camera endpoints while the fallback access point is active. - Apply a short provisioning timeout and shut down the access point automatically afterward. - Avoid predictable SSIDs that reveal the device type; use a device-specific suffix if discovery is required. - Require the user to replace initial credentials during first-time provisioning. - Rate-limit connection and authentication attempts where supported. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
references/setup-guide.md:131
Finding
Wi-Fi Credentials Are Embedded Directly in Source Code and Firmware<![CDATA[ ## Vulnerability Details **File Location**: `references/setup-guide.md`, lines 131–132 **Vulnerability Type**: Plaintext secret storage **Risk Level**: Medium ### Vulnerable Code ```cpp const char* ssid = "YOUR_WIFI_SSID"; // ← replace with your 2.4GHz WiFi const char* password = "YOUR_WIFI_PASSWORD"; // ← replace ``` ### Technical Analysis The guide instructs users to replace placeholders with real Wi-Fi credentials in the source file. Those credentials consequently remain in plaintext in the project source and are compiled into the firmware image. The source can leak through source-control commits, cloud synchronization, backups, shared archives, support bundles, or workstation compromise. An attacker with physical access to an insufficiently protected ESP32 may also be able to extract the firmware and recover embedded strings if flash encryption and secure boot are not enabled. ### Attack Path 1. The user replaces the placeholders with a real SSID and Wi-Fi password. 2. The credentials are saved in `src/main.cpp` and included in the compiled firmware. 3. The project is accidentally committed, synchronized, backed up, shared, or otherwise exposed; alternatively, an attacker acquires the device and reads unprotected flash. 4. The attacker searches the source or firmware image for embedded strings. 5. The attacker recovers the Wi-Fi credentials. 6. If physically or logically in range, the attacker uses those credentials to join the associated network. ### Impact Assessment Successful exploitation discloses the configured Wi-Fi password. An attacker may then gain the network access associated with that wireless credential, including connectivity to other reachable systems and the camera itself. The ultimate scope depends on network segmentation, wireless range, firewall policy, and whether the disclosed password is reused for other services. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions - Provision credentials at runtime instead of placing them in tracked source files. - Store provisioned credentials in ESP32 nonvolatile storage rather than source code. - Use a local configuration file excluded through `.gitignore` if build-time injection is unavoidable. - Add secret-scanning checks to source-control workflows. - Do not print passwords to serial output or build logs. - Enable ESP32 secure boot and flash encryption for deployments whose hardware and threat model require resistance to firmware extraction. - Use a dedicated IoT network credential rather than a privileged or reused network password. - Rotate the Wi-Fi password immediately if source or firmware containing it is exposed. ]]>

T08 · Insecure Dependencies

Warning
Location
references/setup-guide.md:59
Finding
Unpinned Python Dependencies Are Installed Into the System Environment<![CDATA[ ## Vulnerability Details **File Location**: `references/setup-guide.md`, lines 59–61; also documented in `SKILL.md`, line 18 **Vulnerability Type**: Unsafe and non-reproducible dependency installation **Risk Level**: Medium ### Vulnerable Code From `references/setup-guide.md`: ```text - **PlatformIO CLI**: `pip3 install --break-system-packages platformio` - **esptool**: `pip3 install --break-system-packages esptool` (PlatformIO bundles it, but standalone install is handy) - **pyserial**: `pip3 install --break-system-packages pyserial` (for serial communication) ``` From `SKILL.md`: ```text - **Tools**: PlatformIO CLI (`pip3 install platformio`), pyserial (`pip3 install pyserial`) ``` ### Technical Analysis The installation commands do not pin package versions or verify artifact hashes. Installation results can therefore change over time as package and transitive-dependency releases change. The setup guide also uses `--break-system-packages`, which bypasses protections intended to keep pip-managed packages separate from an operating system's managed Python environment. This can overwrite or conflict with host dependencies and makes rollback and reproducibility more difficult. No evidence was found that the named packages are intentionally malicious. The risk arises from mutable dependency resolution, transitive supply-chain exposure, and modification of the system Python environment. ### Attack Path 1. The user executes the documented pip commands. 2. Pip resolves the latest available versions of the named packages and their transitive dependencies from its configured index. 3. A compromised release, compromised package account, unsafe mirror, or future malicious transitive dependency is selected; alternatively, incompatible packages replace system-managed versions. 4. Package installation logic or the installed command executes with the invoking user's privileges. 5. A malicious dependency could access files and credentials available to that ...[truncated 567 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Install command-line applications with `pipx` or use a dedicated Python virtual environment. - Remove `--break-system-packages` from the recommended procedure. - Pin reviewed package versions and relevant transitive dependencies. - Use a lock file or constraints file with cryptographic hashes, such as pip's `--require-hashes` workflow. - Specify and validate the expected package index rather than relying on an uncontrolled pip configuration. - Periodically review and update pinned versions through a controlled dependency-update process. - Prefer PlatformIO's bundled tooling where possible instead of installing redundant packages globally. - Run installation and build processes as an unprivileged user. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (5)

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The skill instructs users to deploy an HTTP camera server exposing `/capture` and `/stream`, but it does not warn that these endpoints make live images available to any device on the local network unless additional controls are added. This can lead to unintended surveillance exposure, privacy leakage, and easy access by other systems on the same WiFi, especially in home or shared-network environments.

Context-Inappropriate Capability

Medium
Confidence
99% confidence
Finding
The HTTP server registers /capture and /stream endpoints with no authentication, authorization, or transport protection. Any host on the same network—or any client connected to the fallback AP—can retrieve snapshots or live video, which is especially sensitive because this skill is specifically for giving agents physical vision. The added CORS wildcard also broadens access from browser-based clients.

Description-Behavior Mismatch

Medium
Confidence
97% confidence
Finding
The firmware falls back to AP mode with a hardcoded, predictable SSID and password, then immediately starts the camera server. Anyone within radio range who knows or guesses the default credentials can join and access the device, and the fixed password is weak because it is reused across deployments. In the context of a camera sensor, this creates direct privacy and surveillance exposure.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The fallback AP uses a predictable network name and documented default password without warning users that nearby parties may connect and view the camera feed. Because this is a visual sensor deployment guide, the omission is more dangerous than for a generic embedded demo: it can expose live images from physical environments to anyone in range. The problem is compounded by the unauthenticated HTTP camera service started in AP mode.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The guide explicitly instructs users to expose capture and live-stream endpoints on the LAN without any accompanying warning about privacy, consent, or network trust assumptions. While documentation alone is not code execution, here it operationalizes insecure deployment of a camera, making accidental surveillance exposure more likely. In this skill context, omission of security guidance materially increases risk.

Static analysis

No suspicious patterns detected.