Back to skill

Security audit

node-camera

Security checks for vulnerabilities and agentic risk

Overview

This camera skill is review-worthy because it handles sensitive live images with unclear shutdown and network-security boundaries, plus an overbroad helper download command.

Install only if you trust the paired Node device and network, understand that camera frames may expose private spaces, and are comfortable with images being served over HTTP and pushed through cloud events. Treat camera.close as stopping callbacks rather than guaranteed hardware shutdown, and avoid passing untrusted URLs, base64 frame data, or output paths to the helper script.

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

Warning
Location
scripts/camera_helper.py:18
Finding

Unrestricted URL Retrieval and Arbitrary File Overwrite

Content
View full analysis

Vulnerability Details

File Location: scripts/camera_helper.py, lines 18-37 and 72-87
Vulnerability Type: Server-Side Request Forgery and Arbitrary File Write
Risk Level: Medium

Vulnerable Code

python
def download_image(url: str, output_path: str):
    """Download an image from the Node device HTTP server."""
    try:
        urllib.request.urlretrieve(url, output_path)
        size_kb = Path(output_path).stat().st_size / 1024
        print(f"Image downloaded: {output_path} ({size_kb:.1f} KB)")
        return True
    except Exception as e:
        print(f"Download failed: {e}")
        return False


def decode_base64_frame(frame_data: str, output_path: str):
    """Decode a Base64 image frame and save it."""
    try:
        if "," in frame_data:
            frame_data = frame_data.split(",")[1]

        image_bytes = base64.b64decode(frame_data)
        Path(output_path).write_bytes(image_bytes)
        print(f"Image saved: {output_path}")
        return True
    except Exception as e:
        print(f"Decode failed: {e}")
        return False

The command-line arguments and dispatch logic that expose these operations are:

python
parser.add_argument('--download', help='Download an image from the Node HTTP server (URL)')
parser.add_argument('--decode-frame', help='Base64 frame data file path')
parser.add_argument('--output', '-o', default='output.jpg', help='Output image path')
parser.add_argument('--analyze', help='Analyze a frame JSON file')
args = parser.parse_args()

if args.download:
    success = download_image(args.download, args.output)
    sys.exit(0 if success else 1)

elif args.decode_frame:
    frame_data = Path(args.decode_frame).read_text().strip()
    success = decode_base64_frame(frame_data, args.output)
    sys.exit(0 if success else 1)

The snippets above are translated into English for explanatory consistency; the execu ...[truncated 3526 chars]

Remediation
View remediation

Remediation Suggestions

  1. Apply a strict URL allowlist

    • Permit only the schemes required by the Skill, preferably plain http only if the Node protocol cannot support TLS.
    • Require the configured paired Node hostname or IP address.
    • Require port 18790.
    • Require the normalized URL path to begin with /images/.
    • Reject embedded credentials, fragments, unexpected query parameters, and malformed authority components.
  2. Validate resolved addresses

    • Resolve the hostname before connecting.
    • Reject loopback, link-local, multicast, unspecified, and unrelated private or internal addresses unless the configured paired Node explicitly uses an approved private address.
    • Revalidate redirects and either disable them or enforce the same allowlist on every redirect target.
    • Consider DNS rebinding by ensuring that the validated address is the address used for the connection.
  3. Restrict output destinations

    • Create a dedicated output directory with restrictive permissions.
    • Resolve the requested destination with Path.resolve().
    • Verify that the resolved destination remains beneath the approved output directory.
    • Reject absolute paths, parent-directory traversal, symlink destinations, and special files.
    • Refuse to overwrite existing files by default, using exclusive creation or a safely generated filename.
  4. Limit resource consumption

    • Replace urlretrieve with controlled streaming that applies explicit connection and read timeouts.
    • Enforce a maximum response size before and during download.
    • Enforce maximum input and decoded sizes for Base64 frames.
    • Decode with strict validation, such as base64.b64decode(frame_data, validate=True).
  5. Validate downloaded content

    • Check the HTTP status and expected content type.
    • Verify the JPEG signature and parse the image with a safe image decoder before accepting it.
    • Delet ...[truncated 447 chars]
Vulnerability Patterns
  • 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
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (10)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The documented behavior promises active camera capture, streaming, stop, and close semantics, while the analysis indicates those functions are not actually implemented and may only download existing images or decode prior frame data. This kind of description-behavior mismatch is dangerous because operators may rely on privacy, lifecycle, or safety guarantees that do not exist, leading to stale-data use, failed shutdown assumptions, or unexpected exposure of previously captured images.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
86% confidence
Finding

The skill documents camera control, HTTP image serving, and cloud/event streaming, but it does not declare any explicit tool scope such as permissions or allowed-tools. That omission weakens least-privilege boundaries and makes it harder for platforms or reviewers to understand and constrain file/network behaviors before deployment.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill is explicitly designed for remote screenshot capture and real-time environmental monitoring, yet it does not prominently warn about privacy implications, consent requirements, or sensitive-scene capture. Because this capability observes a physical environment, misuse can directly enable covert surveillance or collection of confidential visual information.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The documentation claims camera.captureFrame automatically stops streaming and closes the camera after one frame, but later sections state the service does not control actual hardware closure. In a remote camera skill, false assurances about automatic teardown are risky because they may leave capture components active or cause consumers to misunderstand when sensitive collection ends.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill serves images over plain HTTP on a device-local server and describes cloud frame delivery without any warning about confidentiality, integrity, or network exposure. Unencrypted image URLs can be intercepted or modified on the network, and exposing frames via predictable local endpoints increases the chance of unauthorized access to sensitive visual data.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

camera.close is presented as closing and releasing the USB camera, but the same documentation says it only stops streaming callbacks and does not actually close the hardware camera. This ambiguous shutdown contract can cause users or automations to believe monitoring has ended when the camera stack may still be active, creating privacy and resource-management risk.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

This code file contains natural-language docstrings, usage examples, argument help, and status messages exclusively in Chinese. Under the policy rules, forcing a specific language without user opt-in or a documented regional justification is a natural-language policy violation.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The helper exposes a generic file-download primitive via user-supplied URL without restricting scheme, host, or path to the declared Node camera endpoint. In the context of an agent skill, this broadens capability from camera assistance to arbitrary network retrieval, which can be abused for SSRF-like access to internal services or downloading unintended content onto the host.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The CLI wiring makes the unrestricted download capability directly reachable from user input, with no guardrails around destination URL or fetched content. Because the skill is supposed to control a USB camera, this excess capability is not necessary for minimum function and increases risk if an agent or user can be influenced to fetch arbitrary URLs.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

The natural-language content of the skill is consistently Chinese and does not provide an opt-in language choice or explain that the skill is restricted to a Chinese-speaking audience for a justified regional reason. The policy category explicitly calls for flagging forced language or locale behavior without user opt-in.

Content

No source excerpt is available for this finding.