Back to skill

Security audit

IdleClaw

Security checks for vulnerabilities and agentic risk

Overview

IdleClaw is a disclosed community Ollama inference-sharing skill; its network and local Ollama behavior matches its stated purpose, though users should treat shared prompts and dependency installation carefully.

Install only if you are comfortable sending prompts, responses, model names, and contributor-node metadata through the IdleClaw routing service or a server you configure. Avoid using plaintext http:// servers except local development, avoid sensitive prompts, and prefer installing dependencies in a dedicated virtual environment.

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)

T08 · Insecure Dependencies

Warning
Location
install.sh:30
Finding
Unpinned and Unverified Third-Party Dependencies<![CDATA[ ## Vulnerability Details **File Location**: `install.sh:30-31`, `requirements.txt:1-4` **Vulnerability Type**: Supply-chain exposure through mutable dependency resolution **Risk Level**: Medium ### Vulnerable Code ```bash # install.sh:30-31 echo "Installing Python dependencies..." pip install -r "$SCRIPT_DIR/requirements.txt" ``` ```text # requirements.txt:1-4 ollama>=0.4,<1.0 websockets>=14.0,<15.0 python-dotenv>=1.0,<2.0 httpx>=0.27,<1.0 ``` ### Technical Analysis The installer resolves dependencies from broad version ranges without exact version pins, package hashes, or a reviewed lock file. Consequently, the code installed on a future invocation may differ from the code that was available during this audit. Python package installation may execute package-controlled build or installation logic. If a dependency publisher account, package release, package index, or software distribution path is compromised, a malicious version satisfying one of these ranges could be selected and installed. The installation command also targets the currently active Python environment instead of creating a dedicated virtual environment, increasing the scope of any dependency conflict or compromise. The package names do not show evidence of typosquatting or dependency confusion in the audited files. The issue is the absence of reproducible, integrity-verified dependency resolution. ### Attack Path 1. An attacker compromises an allowed dependency release, its publisher account, or the package distribution path. 2. The attacker publishes a malicious version that remains within a configured version range. 3. A user runs `bash install.sh`. 4. `pip` resolves the new mutable version because no exact version or cryptographic hash is required. 5. Package-controlled installation or runtime code executes with the privileges of the user running the installer. 6. The compromised package can affect the Skill whenever its Python scripts import or invoke that dependency. ## ...[truncated 482 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin every direct and transitive dependency to an exact, reviewed version. 2. Generate a lock file containing cryptographic hashes, for example with `pip-compile --generate-hashes`. 3. Install with hash verification enabled: ```bash python3 -m pip install --require-hashes -r requirements.lock ``` 4. Create and use a dedicated virtual environment rather than modifying the active Python environment: ```bash python3 -m venv "$SCRIPT_DIR/.venv" "$SCRIPT_DIR/.venv/bin/python" -m pip install --require-hashes -r "$SCRIPT_DIR/requirements.lock" ``` 5. Review dependency updates before regenerating the lock file and use automated vulnerability and provenance scanning. 6. Avoid running the installer with administrative privileges. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/config.py:11
Finding
Plaintext Routing Endpoints Permit Interception and Modification of Inference Traffic<![CDATA[ ## Vulnerability Details **File Location**: `scripts/config.py:11-17`, `scripts/consume.py:12-21`, `scripts/contribute.py:112-127` **Vulnerability Type**: Plaintext transmission of potentially sensitive prompts, responses, and node metadata **Risk Level**: Medium ### Vulnerable Code ```python # scripts/config.py:11-17 def get_server_url() -> str: """Read and validate the server URL from environment.""" url = os.environ.get("IDLECLAW_SERVER", DEFAULT_SERVER) if not re.match(r"^https?://", url): print(f"Warning: IDLECLAW_SERVER '{url}' is not an HTTP/HTTPS URL. Using default: {DEFAULT_SERVER}", file=sys.stderr) return DEFAULT_SERVER return url.rstrip("/") ``` ```python # scripts/consume.py:12-21 def stream_chat(server_url: str, model: str, prompt: str) -> None: """Send a chat request and stream the response.""" url = f"{server_url}/api/chat" payload = { "model": model, "messages": [{"role": "user", "content": prompt}], } try: with httpx.stream("POST", url, json=payload, timeout=120) as response: ``` ```python # scripts/contribute.py:112-127 async def run_node(server_url: str, models: list[dict], ollama_version: str) -> None: """Connect to server, register, and handle inference requests.""" node_id = str(uuid.uuid4()) ws_url = server_url.replace("https://", "wss://").replace("http://", "ws://") + "/ws/node" logger.info("Connecting to %s", ws_url) ws = await websockets.connect(ws_url) # Register await ws.send(json.dumps({ "type": "register", "node_id": node_id, "models": models, "max_concurrent": 2, "ollama_version": ollama_version, })) ``` ### Technical Analysis The URL validation explicitly accepts both `https://` and plaintext `http://` endpoints. Consumer mode consequently sends the model name and complete prompt over plaintext HTTP when such an endpoint is configured. Contributor mode converts ...[truncated 2146 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Require `https://` for routing-server URLs and use only `wss://` for contributor WebSocket connections. 2. Parse URLs with `urllib.parse.urlparse` rather than validating them with a prefix regular expression. 3. Reject malformed URLs, embedded credentials, fragments, unexpected schemes, and missing hostnames. 4. If plaintext transport is required for local development, allow it only for explicit loopback addresses such as `127.0.0.1`, `::1`, or `localhost`. 5. Gate any local plaintext exception behind a dedicated opt-in setting and print a prominent security warning. 6. Preserve normal TLS certificate and hostname verification. Do not introduce a general-purpose certificate-verification bypass. 7. Consider authenticating contributor sessions and signing or otherwise integrity-protecting routing messages, particularly when custom routing servers are supported. 8. Document that prompts and inference responses are sensitive data and must not be sent to untrusted routing servers. ]]>
Vulnerability Patterns
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (7)

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill invokes Python and Bash and explicitly performs outbound network communication, but it does not declare a restrictive tool scope such as permissions or allowed-tools. This creates a trust gap where the runtime may expose broader capabilities than users expect, increasing the risk of unauthorized network access or environment-variable use if the scripts behave differently than documented or are later modified.

Context-Inappropriate Capability

Medium
Confidence
90% confidence
Finding
The node forwards tool_calls emitted by the local Ollama model back to the community server, even though comments claim no local tool execution occurs. While this code does not execute tools locally, relaying tool call structures can still enable downstream systems to act on model-suggested tool invocations, creating a confused-deputy risk if the server or consumers treat them as trusted actions.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
This skill connects to a community server, registers the local node, and accepts remote inference requests that are processed by the user's local Ollama instance, but the code provides only operational logging and no meaningful consent or warning about the privacy implications. In this context, the skill's stated purpose is community inference sharing, which makes the behavior intentional, but it still risks users exposing model outputs, prompts, and possibly tool-related metadata to third parties without sufficiently explicit disclosure at runtime.

Unverifiable Dependency: websockets has 4 known advisory(ies) (CVE-2018-1000518 (websockets is vulnerable to denial of service by memory exhaustion); CVE-2021-33880 (Observable Timing Discrepancy in aaugustin websockets library); CVE-2018-1000518 (aaugustin websockets version 4 contains a CWE-409: Improper Handling of Highly C) +1 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
90% confidence
Finding
The dependency is range-pinned (`>=14.0,<15.0`) rather than locked to a specific vetted release, so builds may resolve to different `websockets` versions over time without assurance that all known vulnerable releases are excluded. In a skill that participates in community/shared inference and uses network communication, an affected websocket library could increase exposure to denial-of-service or protocol-handling weaknesses.

Unverifiable Dependency: python-dotenv has 2 known advisory(ies) (CVE-2026-28684 (python-dotenv: Symlink following in set_key allows arbitrary file overwrite via ); CVE-2026-28684 (python-dotenv reads key-value pairs from a .env file and can set them as environ)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
80% confidence
Finding
`python-dotenv` is specified as a broad version range (`>=1.0,<2.0`) instead of an exact patched version, so the installed package may vary and could include vulnerable releases. While this package is less exposed than a network stack, dotenv handling can still become security-relevant if the skill writes `.env` files or operates in environments where symlink attacks or unsafe file writes are possible.

Unverifiable Dependency: httpx has 2 known advisory(ies) (CVE-2021-41945 (Improper Input Validation in httpx); CVE-2021-41945 (Encode OSS httpx <=1.0.0.beta0 is affected by improper input validation in `http)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
86% confidence
Finding
`httpx` is not fixed to a single reviewed version, leaving uncertainty about whether installations will pick a release affected by known input-validation issues. Because this skill interacts with community inference and likely makes outbound HTTP requests, weaknesses in an HTTP client can matter more here than in an offline-only tool.

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Content
message = chunk.get("message", {})
        msg_dict: dict = {}
        for key in ("role", "content", "thinking", "tool_calls"):
            val = message.get(key) if isinstance(message, dict) else getattr(message, key, None)
            if val is not None and val != "" and val != []:
                if key == "tool_calls" and isinstance(val, list):
                    val = [tc.model_dump() if hasattr(tc, "model_dump") else tc for tc in val]
Confidence
50% confidence
Finding
Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Static analysis

No suspicious patterns detected.