Back to skill

Security audit

Molecular 3D Renderer

Security checks for vulnerabilities and agentic risk

Overview

This skill coherently renders molecule images and the risky behaviors found are expected for that purpose, though users should be aware of network downloads, external rendering, and shared temporary-file cache risks.

Install in a virtual environment as a non-privileged user, prefer pinned dependency versions, and be aware that entering a 4-character PDB ID makes a network request to RCSB. In shared or multi-user systems, avoid trusting the default PDB cache in the system temp directory; use local PDB files or review/cache them in a private directory when possible.

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
SKILL.md:8
Finding
Unpinned Third-Party Dependencies Create Supply-Chain Risk## Vulnerability Details **File Location**: `SKILL.md`, lines 8-10 and 28-32 **Vulnerability Type**: Unpinned and unverifiable third-party dependencies **Risk Level**: Medium ### Vulnerable Code ```yaml metadata: openclaw: emoji: "🧪" requires: bins: ["povray", "python3"] pip: ["rdkit", "numpy"] optionalPip: ["biopython"] ``` ```bash pip install rdkit numpy apt-get install -y povray # For PDB support: pip install biopython ``` ### Technical Analysis The Skill declares and recommends installing `rdkit`, `numpy`, and `biopython` without exact version constraints or package-integrity hashes. Dependency resolution therefore selects whichever compatible versions are available from the configured package index at installation time. This makes installations non-reproducible and leaves the Skill exposed to upstream package compromise, malicious releases, compromised package indexes, or unsafe index configuration. The project does not provide a lock file, hashes, or an explicitly trusted package source that would allow users to verify that the installed artifacts are the versions reviewed by the Skill author. The package names appear legitimate, and no direct evidence of a currently malicious dependency was identified. The risk arises from the unsafe dependency-management practice rather than from a confirmed compromise of those packages. ### Attack Path 1. An attacker compromises an upstream dependency release, its distribution account, a configured package index, or the dependency-resolution path. 2. The attacker publishes or serves a malicious version under one of the names accepted by the unpinned installation commands. 3. A user follows the documented `pip install` command, or the agent framework automatically resolves the dependencies from the metadata. 4. The malicious package is installed because no version or artifact hash is enforced. 5. Attacker-controlled code execut ...[truncated 688 chars]
Remediation
## Remediation Suggestions 1. Pin every Python dependency to a reviewed version in a dedicated requirements file or lock file. 2. Generate and enforce cryptographic hashes for all resolved artifacts, for example with `pip-tools` and `pip install --require-hashes`. 3. Pin transitive dependencies as well as direct dependencies to make builds reproducible. 4. Explicitly configure a trusted package index and prevent fallback to untrusted or unintended indexes. 5. Install dependencies in a dedicated virtual environment under a non-privileged account. 6. Add automated dependency vulnerability and provenance scanning to the release process. 7. Document a controlled upgrade procedure requiring review and testing before dependency pins are changed. Example hardened installation pattern: ```bash python3 -m venv .venv . .venv/bin/activate python3 -m pip install --require-hashes -r requirements.lock ```

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/pdb_to_3d.py:61
Finding
Predictable Shared Temporary PDB Cache Permits Local File Substitution## Vulnerability Details **File Location**: `scripts/pdb_to_3d.py`, lines 61-78 **Vulnerability Type**: Unsafe predictable temporary-file handling **Risk Level**: Medium ### Vulnerable Code ```python def download_pdb(pdb_id: str, out_dir: str = None) -> str: """Download PDB file from RCSB.""" pdb_id = pdb_id.upper() url = f"https://files.rcsb.org/download/{pdb_id}.pdb" if out_dir is None: out_dir = tempfile.gettempdir() out_path = os.path.join(out_dir, f"{pdb_id}.pdb") if os.path.exists(out_path): print(f"Using cached PDB: {out_path}") return out_path print(f"Downloading PDB {pdb_id} from RCSB...") try: urllib.request.urlretrieve(url, out_path) except Exception as e: raise RuntimeError(f"Failed to download PDB {pdb_id}: {e}") print(f"Downloaded to {out_path}") return out_path ``` ### Technical Analysis Downloaded PDB files are stored under the system-wide temporary directory using a predictable filename derived from a four-character PDB identifier, such as `/tmp/1ABC.pdb`. If that path already exists, the code trusts and returns it without verifying ownership, permissions, file type, provenance, or content integrity. This allows another local process or user with access to the shared temporary directory to pre-create a file at the expected path. The victim will then parse attacker-controlled content instead of downloading the requested structure. There is also a check-then-write race between `os.path.exists(out_path)` and `urllib.request.urlretrieve(url, out_path)`. The destination is not created atomically with exclusive semantics, and the code does not reject symbolic links. Under filesystem and permission conditions that allow it, an attacker could replace the path during this interval and attempt to redirect the write. PDB parsing converts untrusted fields to integers and floating-point values and performs potenti ...[truncated 2000 chars]
Remediation
## Remediation Suggestions 1. Do not store trusted cache entries directly in the shared system temporary directory. 2. Create a private temporary directory with `tempfile.TemporaryDirectory()` or `tempfile.mkdtemp()` and restrictive permissions. 3. If persistent caching is required, use a user-owned cache directory such as one derived from `platformdirs.user_cache_dir()` and enforce mode `0700` on the directory. 4. Create destination files atomically with exclusive creation semantics and restrictive permissions. 5. Reject symbolic links and non-regular files by using `lstat()` or descriptor-based checks. 6. Download to a unique temporary file, validate it as a plausible PDB document, flush and close it, and then atomically move it into the cache with `os.replace()`. 7. Apply download-size limits, network timeouts, parser limits, and atom-count limits to reduce denial-of-service exposure. 8. Consider recording and verifying a content digest for cached entries when an authoritative digest is available. A safer high-level pattern is: ```python with tempfile.TemporaryDirectory(prefix="mol-render-") as private_dir: temporary_path = os.path.join(private_dir, f"{pdb_id}.pdb") # Download with explicit timeout and size limits. # Validate the file before parsing or moving it into a private cache. ``` For a persistent cache, ensure the directory is private, verify that an existing entry is a regular file owned by the current user, and never trust a file solely because its predictable pathname already exists.
Vulnerability Patterns
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • 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 (5)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The implemented behavior substantially matches the core declared purpose of producing 3D ball-and-stick molecular renderings via POV-Ray from molecular input. However, the code only accepts a positional SMILES string and contains no parser, loader, or handling for PDB files or structures. That makes the description materially broader than the actual implementation. No other suspicious or unrelated capabilities are evident: subprocess use is limited to calling POV-Ray for rendering, and there is no evidence of network access, data exfiltration, or unrelated system actions.

Lp3

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding
The skill documentation declares no explicit tool scope or permissions even though its described behavior includes shell execution, file reads, and network access. This weakens sandboxing and user consent because an agent may invoke external binaries or fetch remote data without a clearly declared boundary.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
'-D',          # no display
            '+UA',         # output alpha
        ]
        result = subprocess.run(cmd, capture_output=True, text=True, timeout=120)
        if result.returncode != 0:
            print(f"POV-Ray stderr: {result.stderr}", file=sys.stderr)
            raise RuntimeError(f"POV-Ray failed with code {result.returncode}")
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Missing User Warnings

Low
Confidence
94% confidence
Finding
This markdown file documents that `--pdb` accepts a 4-character PDB ID and will auto-download from RCSB, which is a network operation. The README explains the behavior functionally but does not include any explicit warning about outbound network access or fetching remote data, which falls under missing user warnings for markdown files.

Natural-Language Policy Violations

Low
Confidence
84% confidence
Finding
This code file contains user-facing natural-language text in Chinese in the main module docstring, while the rest of the interface is mixed-language and there is no indication that the tool is intentionally region-specific or that users can choose their preferred language. Under the stated policy, forcing a specific language without opt-in is a locale-policy concern.

Static analysis

No suspicious patterns detected.