Back to skill

Security audit

OctoClaw

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly a real OctoPrint helper, but it controls physical printer hardware and sends data externally without enough safety limits or scoping.

Install only if you are comfortable giving the agent control over a real 3D printer and outbound Telegram notifications. Use HTTPS for OctoPrint, a least-privileged API key, restrict config.json permissions, avoid telegram-msg for sensitive content, confirm every print/temperature/cancel action manually, and limit uploads and snapshots to known safe directories and G-code/image files.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/octoprint.py:35
Finding
OctoPrint API Credentials May Be Transmitted over Plaintext HTTP<![CDATA[ ## Vulnerability Details **File Location**: `scripts/octoprint.py:35-49`; insecure default in `config.example.json:2-3` **Vulnerability Type**: Plaintext transmission of an API credential **Risk Level**: High ### Vulnerable Code ```python def make_request(method, endpoint, **kwargs): """Make a request to Octoprint API""" config = load_config() url = f"{config['octoprint_url']}{endpoint}" headers = {"X-Api-Key": config["api_key"]} if "headers" in kwargs: kwargs["headers"].update(headers) else: kwargs["headers"] = headers try: response = requests.request(method, url, **kwargs, timeout=10) response.raise_for_status() ``` The example configuration explicitly recommends an unencrypted endpoint: ```json { "octoprint_url": "http://octopi.local", "api_key": "YOUR_API_KEY_HERE" } ``` The upload path repeats the same behavior at `scripts/octoprint.py:521-529`: ```python config = load_config() url = f"{config['octoprint_url']}/api/files/local" headers = {"X-Api-Key": config["api_key"]} with open(filepath, 'rb') as f: files = {'file': (filename, f, 'application/octet-stream')} response = requests.post(url, headers=headers, files=files, timeout=30) response.raise_for_status() ``` ### Technical Analysis The script places the OctoPrint API key in the `X-Api-Key` header without requiring HTTPS. Because the supplied example uses `http://octopi.local`, a normal installation based on that example transmits the credential and all printer commands without transport encryption. An attacker capable of observing or manipulating the local network can capture the API key, inspect uploaded G-code, alter API responses, or inject and replay control requests. The use of a `.local` hostname also makes endpoint integrity dependent on local name resolution and network trust. Authenticated network access is necessary for the declared OctoPrint functionality, but plaintext credential transport is no ...[truncated 1328 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Require `https://` for `octoprint_url` by default and reject plaintext HTTP unless the user explicitly enables a clearly documented compatibility override. 2. Replace the HTTP URLs in `config.example.json` with HTTPS examples. 3. Preserve TLS certificate verification and provide a documented way to trust a private CA rather than recommending `verify=False`. 4. Use a dedicated, least-privileged OctoPrint application key instead of an administrator-level key. 5. Warn prominently when an insecure endpoint is configured and require explicit confirmation before sending credentials. 6. Consider supporting environment variables or an operating-system secret store for the API key. 7. Apply the same validated URL construction to both `make_request()` and `upload_file()` so no secondary request path bypasses the transport policy. 8. Document network segmentation and advise users not to expose OctoPrint directly to untrusted networks. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/octoprint.py:324
Finding
Snapshot Command Allows Arbitrary File Overwrite and Symbolic-Link Following<![CDATA[ ## Vulnerability Details **File Location**: `scripts/octoprint.py:324-342` **Vulnerability Type**: Unrestricted output path and unsafe file creation **Risk Level**: Medium ### Vulnerable Code ```python def get_snapshot(output_path=None): """Capture webcam snapshot""" config = load_config() # Get webcam URL from config or use default webcam_url = config.get("webcam_url", f"{config['octoprint_url']}/webcam/?action=snapshot") try: response = requests.get(webcam_url, timeout=10) response.raise_for_status() # Determine output path if output_path is None: output_path = f"/tmp/octoprint_snapshot_{datetime.now().strftime('%Y%m%d_%H%M%S')}.jpg" with open(output_path, 'wb') as f: f.write(response.content) print(f"Snapshot saved to: {output_path}") return output_path ``` The path is supplied directly from the command line at `scripts/octoprint.py:575-577`: ```python elif command == "snapshot": output = sys.argv[2] if len(sys.argv) > 2 else None get_snapshot(output) ``` ### Technical Analysis The snapshot output path is accepted without restricting its destination, checking whether it already exists, or preventing symbolic-link traversal. Opening the path with mode `wb` truncates an existing file before writing attacker-influenced network content into it. The impact is bounded by the operating-system privileges of the process. However, skills are often run by an agent with access to user configuration, workspace files, SSH configuration, or other sensitive writable files. A malicious or mistaken invocation can therefore destroy or replace any file writable by that account. The generated default filename also uses a predictable second-resolution name under the shared `/tmp` directory. A local attacker could pre-create that path as a symbolic link before the snapshot is written. ### Attack Path **Explicit-path attack:** 1. An attacker causes th ...[truncated 1106 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Save snapshots to a dedicated application-owned directory with restrictive permissions. 2. Generate default files using `tempfile.NamedTemporaryFile(delete=False, suffix=".jpg")` or `tempfile.mkstemp()` rather than predictable timestamp-only names. 3. If custom output paths are required, resolve and validate them against an explicitly allowed directory. 4. Refuse to overwrite existing files unless the user supplies an explicit overwrite option. 5. Create files atomically with exclusive creation semantics, such as mode `xb`. 6. Where supported, use `os.open()` with `O_CREAT | O_EXCL | O_NOFOLLOW` and restrictive permissions such as `0o600`. 7. Check the response content type and enforce a maximum response size before writing it. 8. Run the skill as an unprivileged account with access only to the required output directory. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/octoprint.py:505
Finding
Unbounded Temperature Commands Can Request Unsafe Heater Targets<![CDATA[ ## Vulnerability Details **File Location**: `scripts/octoprint.py:505-511` **Vulnerability Type**: Missing safety validation for physical-device control **Risk Level**: High ### Vulnerable Code ```python def set_temperature(tool, temp): """Set tool or bed temperature""" if tool == "bed": make_request("POST", "/api/printer/bed", json={"command": "target", "target": int(temp)}) else: make_request("POST", "/api/printer/tool", json={"command": "target", "targets": {tool: int(temp)}}) print(f"Set {tool} temperature to {temp}°C") ``` Command-line input is passed directly to this function at `scripts/octoprint.py:590-594`: ```python elif command == "temp": if len(sys.argv) < 4: print("Error: Missing tool and temperature", file=sys.stderr) sys.exit(1) set_temperature(sys.argv[2], sys.argv[3]) ``` ### Technical Analysis The command converts the supplied temperature to an integer but imposes no minimum or maximum temperature and does not strictly validate the tool identifier. Every identifier other than the exact string `bed` is forwarded as a tool target. The script therefore relies entirely on OctoPrint and printer firmware to reject unsafe targets. Firmware thermal limits are an important final safety layer, but they should not be the only validation layer exposed through an AI-controlled skill. A misconfiguration, compromised plugin, permissive profile, or unsafe firmware limit could allow temperatures outside the hardware or material's safe operating range. The ability to set heater temperatures is declared functionality and thus necessary, but accepting arbitrary values without a safety policy is broader than the minimum privilege and control surface needed. ### Attack Path 1. A malicious instruction, user mistake, or compromised upstream workflow causes the agent to invoke `temp` with an excessive target, such as an abnormally high bed or hotend temperature. 2. The script accepts the intege ...[truncated 838 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Allow only explicit tool identifiers such as `bed` and `tool0`, or dynamically validate tools against the active printer profile. 2. Define conservative configurable limits separately for each heater, including minimum and maximum bed and hotend temperatures. 3. Reject non-integer, negative, and out-of-range values before making any network request. 4. Keep software limits at or below the printer profile and hardware manufacturer's limits. 5. Require explicit user confirmation for unusually high temperatures and for heating when no print is active. 6. Add a dry-run or display-only validation step so the agent can show the proposed target before applying it. 7. Record safety-relevant commands without logging API credentials. 8. Retain and test firmware thermal-runaway protection; application validation must supplement rather than replace firmware safeguards. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/octoprint.py:348
Finding
Telegram Bot Token Can Be Disclosed Through Logged Request Errors<![CDATA[ ## Vulnerability Details **File Location**: `scripts/octoprint.py:348-369` and `scripts/octoprint.py:373-400` **Vulnerability Type**: Secret embedded in URL and potentially emitted in error output **Risk Level**: Medium ### Vulnerable Code ```python def send_telegram_message(message): """Send a text message via Telegram""" config = load_config() if "telegram_bot_token" not in config or "telegram_chat_id" not in config: print("Error: Telegram not configured. Add telegram_bot_token and telegram_chat_id to config.json", file=sys.stderr) sys.exit(1) url = f"https://api.telegram.org/bot{config['telegram_bot_token']}/sendMessage" try: response = requests.post(url, json={ "chat_id": config["telegram_chat_id"], "text": message, "parse_mode": "Markdown" }, timeout=10) response.raise_for_status() print("Telegram message sent successfully") except requests.exceptions.RequestException as e: print(f"Error sending Telegram message: {e}", file=sys.stderr) sys.exit(1) ``` The photo path uses the same pattern: ```python url = f"https://api.telegram.org/bot{config['telegram_bot_token']}/sendPhoto" try: with open(image_path, 'rb') as f: files = {'photo': f} data = { "chat_id": config["telegram_chat_id"] } if caption: data["caption"] = caption response = requests.post(url, files=files, data=data, timeout=30) response.raise_for_status() print("Telegram photo sent successfully") except requests.exceptions.RequestException as e: print(f"Error sending Telegram photo: {e}", file=sys.stderr) sys.exit(1) ``` ### Technical Analysis Telegram's Bot API requires the bot token as part of the request URL. The script then prints the complete `requests` exception object to standard error. Connection errors, proxy failures, and HTTP errors commonly include the reque ...[truncated 1485 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Never print raw exception strings for requests whose URLs contain secrets. 2. Emit a sanitized error containing only the exception class, a fixed operation name, and a safe status code. 3. Implement a redaction function that replaces the configured token with `[REDACTED]` before any diagnostic output. 4. Ensure application, agent, proxy, and HTTP debug logging do not record the token-bearing URL. 5. Store the bot token in an environment variable or operating-system secret store rather than a general configuration file. 6. Restrict `config.json` permissions to the owning account, such as mode `0600`. 7. Rotate the Telegram token immediately if it has appeared in logs or transcripts. 8. Apply the same sanitization to both message and photo request paths. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (16)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The declared description frames the skill as printer control and monitoring, but the documented commands also include Telegram messaging, photo transmission to an external service, direct temperature control, and file upload. This mismatch can mislead users and orchestration systems about the true action surface, causing privacy-impacting or safety-sensitive operations to be invoked without adequate scrutiny or consent.

Ae1

High
Category
analysis-evasion
Content
Helper script: `scripts/octoprint.py` (relative to this skill directory).
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Exfiltration Commands

High
Category
Prompt Injection
Content
print("  upload <file>       - Upload gcode file", file=sys.stderr)
        print("  telegram-status     - Send status to Telegram", file=sys.stderr)
        print("  telegram-snapshot   - Send snapshot to Telegram", file=sys.stderr)
        print("  telegram-msg <msg>  - Send message to Telegram", file=sys.stderr)
        sys.exit(1)

    command = sys.argv[1]
Confidence
93% confidence
Finding
The exposed CLI command for sending Telegram messages advertises an exfiltration-capable feature directly in the tool interface. A generic 'send message' command is not necessary for core printer control and materially increases abuse potential by providing a straightforward outbound channel.

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill declares no explicit tool scope even though its documented behavior requires file access and network communication. Without clear permission boundaries, an agent may invoke this skill in broader contexts than intended, increasing the chance of unintended local file access or networked actions against OctoPrint or related services.

Vague Triggers

Medium
Confidence
94% confidence
Finding
The trigger condition is broad enough to activate on general printer-related questions, including benign informational requests, even though the skill supports real-world actions like print control and temperature setting. Overbroad activation increases the chance that an agent will select this skill unnecessarily and perform or suggest operational actions without sufficiently clear user intent.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The print-control section exposes pause, resume, cancel, print start, and temperature-setting commands without any warning that these are destructive or safety-sensitive actions. In the context of a physical printer, accidental invocation can waste material, damage an in-progress print, or create hardware and fire-risk conditions if temperatures are changed improperly.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The webcam snapshot and Telegram features can capture and transmit images and status data to external destinations, but the markdown provides no privacy warning or consent guidance. This is dangerous because users may not realize that workspace images, printer state, filenames, or progress data could be sent off-device, creating privacy and information-leak risks.

Description-Behavior Mismatch

Medium
Confidence
98% confidence
Finding
The skill adds Telegram outbound messaging and photo transfer capabilities that are not disclosed in the manifest description, expanding the data-flow and control surface beyond expected OctoPrint operations. Hidden or under-disclosed external communications are dangerous because they can be used to export printer status, webcam images, or user-supplied content to a third party without informed consent.

Context-Inappropriate Capability

Medium
Confidence
96% confidence
Finding
Arbitrary Telegram message sending is not necessary for core 3D-printer control and allows user-provided content to be transmitted to an external service. Even if intended as convenience functionality, it creates an exfiltration primitive that can relay sensitive information outside the local printer environment.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
Telegram message sending sends user-provided content to an external third-party service without clear disclosure in the skill context. This is dangerous because it can be used as a general-purpose outbound channel for sensitive data unrelated to printer management.

External Transmission

Medium
Category
Data Exfiltration
Content
print("Error: Telegram not configured. Add telegram_bot_token and telegram_chat_id to config.json", file=sys.stderr)
        sys.exit(1)

    url = f"https://api.telegram.org/bot{config['telegram_bot_token']}/sendMessage"

    try:
        response = requests.post(url, json={
Confidence
90% confidence
Finding
The hardcoded Telegram API endpoint indicates intentional communication with an external service outside OctoPrint. In a printer-control skill, undisclosed third-party communication increases risk because it expands data exposure beyond the local printer system.

External Transmission

Medium
Category
Data Exfiltration
Content
url = f"https://api.telegram.org/bot{config['telegram_bot_token']}/sendMessage"

    try:
        response = requests.post(url, json={
            "chat_id": config["telegram_chat_id"],
            "text": message,
            "parse_mode": "Markdown"
Confidence
95% confidence
Finding
This POST sends message content to Telegram, creating an external transmission path to a third party. Because the content is caller-controlled and not limited to printer telemetry, it can be used to exfiltrate arbitrary information from the skill context.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
Sending webcam snapshots to Telegram exports image data from the local environment to an external service without clear disclosure. In the context of a 3D-printer skill, webcam images may capture the workspace, people, or other sensitive surroundings, making this more dangerous than ordinary printer telemetry.

External Transmission

Medium
Category
Data Exfiltration
Content
print(f"Error: Image file not found: {image_path}", file=sys.stderr)
        sys.exit(1)

    url = f"https://api.telegram.org/bot{config['telegram_bot_token']}/sendPhoto"

    try:
        with open(image_path, 'rb') as f:
Confidence
96% confidence
Finding
This endpoint is used to upload photos to Telegram, enabling external transmission of local image files. In this skill, the likely source is webcam snapshots, which can reveal the user's physical environment and therefore carry higher privacy impact than plain status data.

Context-Inappropriate Capability

Medium
Confidence
91% confidence
Finding
The code can upload local files to OctoPrint, but this capability is not disclosed in the manifest. While file upload is plausibly related to print management, undisclosed local-file transmission broadens the skill's authority and can cause unintended exposure of local data if misused.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The upload operation transmits local file contents over the network to OctoPrint without any explicit user-facing warning at the point of use. This is risky because users may not realize a local file is being sent to a service, and the function accepts arbitrary paths rather than only vetted print artifacts.

Static analysis

No suspicious patterns detected.