Back to skill

Security audit

AutoMD-Viz

Security checks for vulnerabilities and agentic risk

Overview

This skill appears intended for molecular-visualization work, but its shell script can turn crafted file names or options into executable PyMOL or Python code.

Review before installing. Use this only with trusted input files, trusted filenames, and trusted option values, preferably inside an isolated environment. Avoid running it on untrusted projects until the script validates options and passes values to Python/PyMOL as data rather than generated code. Pin dependencies before use if reproducibility or supply-chain control matters.

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

T09 · Insecure Skill Coding Practices

Error
Location
automd-viz.sh:149
Finding
Command Injection Through Generated PyMOL and Python Commands<![CDATA[ ## Vulnerability Details **File Location**: `automd-viz.sh:149-181` **Vulnerability Type**: Injection of untrusted CLI and environment values into executable PyMOL and Python command text **Risk Level**: High ### Vulnerable Code ```bash cat > "${OUTPUT_DIR}/pymol_script.pml" << EOF # PyMOL Publication-Quality Rendering Script load ${structure}, protein hide everything show ${style} color ${color} # High-quality rendering settings set ray_trace_mode, 1 set ray_shadows, 1 set ray_trace_fog, 0 set antialias, 2 set ambient, 0.4 set specular, 0.5 set shininess, 10 set depth_cue, 0 set ray_opaque_background, 1 # View optimization orient zoom # Output ray ${OUTPUT_DPI}, ${OUTPUT_DPI} png ${output}, dpi=${OUTPUT_DPI} quit EOF if command -v pymol &>/dev/null; then pymol -c "${OUTPUT_DIR}/pymol_script.pml" || error "PyMOL execution failed" else python3 -c "import pymol; pymol.cmd.do('run ${OUTPUT_DIR}/pymol_script.pml')" || error "PyMOL execution failed" fi ``` The affected values originate from command-line arguments or environment variables: ```bash OUTPUT_DIR="${OUTPUT_DIR:-publication-viz}" OUTPUT_DPI="${OUTPUT_DPI:-300}" STRUCTURE_STYLE="${STRUCTURE_STYLE:-cartoon}" STRUCTURE_COLOR="${STRUCTURE_COLOR:-spectrum}" ``` ```bash --structure) INPUT_STRUCTURE="$2"; shift 2 ;; --style) STRUCTURE_STYLE="$2"; shift 2 ;; --color) STRUCTURE_COLOR="$2"; shift 2 ;; -o) OUTPUT_DIR="$2"; shift 2 ;; --dpi) OUTPUT_DPI="$2"; shift 2 ;; ``` ### Technical Analysis The script directly interpolates the structure path, rendering style, color, output path, and DPI into a generated PyMOL command file. These values are not escaped and are not restricted to safe character sets or documented allowlists. A value containing a newline or other PyMOL command-language delimiters can change the generated script's command structure and append unintended PyMOL commands. The risk is particularly significant because PyMOL scripting can invoke Python functionality and interac ...[truncated 1951 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Enforce strict allowlists before generating any PyMOL command: - Style: `cartoon`, `surface`, `sticks`, or `spheres`. - Color: a finite set of explicitly supported PyMOL color schemes. - DPI: an integer within a reasonable range, such as 72–1200. - Output format: `png`, `svg`, `pdf`, or `eps`. 2. Reject values containing control characters, carriage returns, or newlines. 3. Avoid generating PyMOL source from interpolated text. Use the PyMOL Python API and pass validated strings as function arguments, for example through `cmd.load`, `cmd.show`, `cmd.color`, and `cmd.png`. 4. Do not embed `OUTPUT_DIR` in `python3 -c`. Pass it as a positional argument: ```bash python3 -c 'import pymol, sys; pymol.cmd.do("run " + sys.argv[1])' \ "${OUTPUT_DIR}/pymol_script.pml" ``` 5. Canonicalize and validate paths. Ensure generated files remain under the intended output directory when that confinement is a security requirement. 6. Add automated tests containing quotes, commas, semicolons, backslashes, newlines, and Unicode control characters to verify that inputs remain data rather than executable syntax. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
automd-viz.sh:232
Finding
Arbitrary Python Code Injection Through Inline Heredoc Interpolation<![CDATA[ ## Vulnerability Details **File Location**: `automd-viz.sh:232-262` and `automd-viz.sh:292-308` **Vulnerability Type**: Untrusted values embedded directly into generated Python source code **Risk Level**: High ### Vulnerable Code The plotting function inserts user-controlled values into Python string literals and expressions: ```python plt.rcParams.update(journal_styles['${style}']) sns.set_palette("husl") # Read data try: if '${data_file}'.endswith('.xvg'): data = np.loadtxt('${data_file}', comments=['#', '@']) else: data = np.loadtxt('${data_file}') except Exception as e: print(f"ERROR: Failed to read data: {e}", file=sys.stderr) sys.exit(1) # Generate plot fig, ax = plt.subplots() plot_type = '${plot_type}' if plot_type == 'timeseries': ax.plot(data[:, 0], data[:, 1], linewidth=1.0) ax.set_xlabel('Time (ps)') ax.set_ylabel('Value') elif plot_type == 'heatmap': sns.heatmap(data, cmap='viridis', ax=ax, cbar_kws={'label': 'Value'}) elif plot_type == 'violin': sns.violinplot(data=data, ax=ax) else: print(f"ERROR: Unknown plot type: {plot_type}", file=sys.stderr) sys.exit(1) plt.tight_layout() plt.savefig('${output}', format='${OUTPUT_FORMAT}', dpi=${OUTPUT_DPI}, bbox_inches='tight') ``` The trajectory function inserts numeric and string values directly into Python syntax: ```python if ${dims} == 2: ax = fig.add_subplot(111) scatter = ax.scatter(data[:, 1], data[:, 2], c=data[:, 0], cmap='viridis', s=1, alpha=0.6) ax.set_xlabel('PC1' if '${method}' == 'pca' else 'Component 1') ax.set_ylabel('PC2' if '${method}' == 'pca' else 'Component 2') plt.colorbar(scatter, label='Time (ps)') else: ax = fig.add_subplot(111, projection='3d') scatter = ax.scatter(data[:, 1], data[:, 2], data[:, 3], c=data[:, 0], cmap='viridis', s=1, alpha=0.6) ax.set_xlabel('PC1') ax.set_ylabel('PC2') ax.set_zlabel('PC3') plt.tig ...[truncated 2762 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Never interpolate user-controlled values into Python source code. 2. Place Python logic in a dedicated `.py` file and pass values through `sys.argv` using a safely quoted argument array: ```bash python3 plot.py \ --data "$data_file" \ --plot-type "$plot_type" \ --output "$output" \ --style "$style" \ --format "$OUTPUT_FORMAT" \ --dpi "$OUTPUT_DPI" ``` 3. If an inline script must be retained, use a single-quoted heredoc delimiter and pass all dynamic values as positional arguments or environment variables: ```bash python3 - "$data_file" "$plot_type" "$output" "$style" \ "$OUTPUT_FORMAT" "$OUTPUT_DPI" <<'PY' import sys data_file, plot_type, output, style, output_format, dpi_text = sys.argv[1:] dpi = int(dpi_text) # Use values as data only. PY ``` 4. Validate all enumerations: - Plot type: `timeseries`, `heatmap`, or `violin`. - Journal style: `nature`, `science`, or `cell`. - Method: only methods actually implemented. - Format: `png`, `svg`, `pdf`, or `eps`. - Dimensions: exactly `2` or `3`. 5. Parse DPI and dimensions as integers and enforce reasonable bounds. 6. Resolve output paths and, where appropriate, verify that they remain beneath the designated output directory. 7. Add regression tests that invoke every option with embedded quotes, newlines, backslashes, and Python metacharacters. ]]>

T08 · Insecure Dependencies

Warning
Location
_meta.json:31
Finding
Unpinned Third-Party Dependencies Permit Non-Reproducible Supply-Chain Resolution<![CDATA[ ## Vulnerability Details **File Location**: `_meta.json:31-44`; also documented in `README.md:144`, `SKILL.md:203`, and `publication-viz-errors.md:31` **Vulnerability Type**: Unpinned dependency installation from the user's configured package index **Risk Level**: Medium ### Vulnerable Code The package metadata permits unrestricted versions: ```json "dependencies": { "python": ">=3.7", "numpy": "*", "matplotlib": "*", "seaborn": "*" }, "optionalDependencies": { "pymol": "*", "scikit-learn": "*", "umap-learn": "*", "MDAnalysis": "*" } ``` The documentation instructs users to install mutable package versions without integrity verification: ```bash pip install numpy matplotlib seaborn scikit-learn umap-learn MDAnalysis ``` ```bash pip3 install matplotlib seaborn numpy scipy pandas ``` ### Technical Analysis Wildcard dependency declarations and unversioned `pip install` commands cause installation results to depend on the packages available from the user's configured index at installation time. The package names observed in the project are not demonstrated to be typosquatted or intentionally malicious. The risk instead arises from unrestricted future resolution, compromised upstream releases, compromised package-index accounts, malicious mirrors, dependency confusion in customized environments, and unexpected breaking changes. No lock file, reviewed version set, package hashes, or trusted index configuration is provided. Consequently, two installations performed at different times may execute different third-party code even though the audited skill files remain unchanged. ### Attack Path 1. A user follows the documented installation instructions or a platform resolves wildcard dependencies from `_meta.json`. 2. The package installer queries the user's configured package index or mirror. 3. A compromised, replaced, or otherwise unreviewed package version is selected because no version or hash constraint prevents it. 4. Package-c ...[truncated 1120 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Create and maintain a reviewed dependency lock file containing exact versions. 2. Generate hashes for all direct and transitive packages and install with integrity enforcement: ```bash python3 -m pip install --require-hashes -r requirements.lock ``` 3. Replace wildcard metadata constraints with tested version constraints. Prefer exact versions in deployable lock files and narrowly bounded compatible ranges in reusable package metadata. 4. Document an explicitly trusted package index, and avoid adding untrusted extra indexes. 5. Install dependencies inside an isolated virtual environment as a non-privileged user. 6. Use automated dependency scanning and scheduled update reviews. Regenerate hashes only after reviewing and testing the new dependency set. 7. Keep optional dependencies separated by feature so users do not install unnecessary packages and enlarge the supply-chain attack surface. ]]>
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • 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
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (7)

Intent-Code Divergence

Medium
Confidence
96% confidence
Finding
The inline help documents `--pymol-script FILE` as a supported structure option, implying users can supply a custom PyMOL script. However, the argument parser never handles `--pymol-script`, and `pymol_structure_viz()` always generates and runs its own script instead, so the documentation contradicts the implemented behavior.

Natural-Language Policy Violations

Medium
Confidence
92% confidence
Finding
The entire skill file is written in Chinese, including the title, troubleshooting steps, and user-facing guidance, with no indication that users may choose another language. Under the stated policy, forcing a specific language without user opt-in is a natural-language policy violation.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
conda install -c conda-forge pymol-open-source

# Ubuntu/Debian
sudo apt-get install pymol

# macOS
brew install pymol
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Missing User Warnings

Low
Confidence
82% confidence
Finding
This is a markdown file, so SQP-2 applies to omissions in user-facing safety disclosures. The report-generation section explicitly states that the tool creates a `figures/` directory and `VISUALIZATION_REPORT.md`, but it does not mention any overwrite or filesystem-impact warning for existing files in the working directory.

Natural-Language Policy Violations

Low
Confidence
78% confidence
Finding
This shell skill contains user-facing descriptions, help text, logs, and errors primarily in Chinese, with some English labels, but does not indicate any language-selection or opt-in mechanism. Under the policy rule for language/locale constraints, hardcoded user-facing language can be a policy concern when no choice is offered.

Intent-Code Divergence

Low
Confidence
90% confidence
Finding
The usage text claims a `--layout GRID` plotting option exists, suggesting plot layout customization is supported. In the implementation, `PLOT_LAYOUT` is never parsed from CLI and is never used by `python_plot()` or elsewhere, so the documented capability is not actually present.

Intent-Code Divergence

Low
Confidence
81% confidence
Finding
The comment presents `trajectory_viz()` as implementing PCA/t-SNE/UMAP visualization. In practice, it simply loads `projection_${method}.xvg` and, on failure, tells the user to run PCA first, indicating the function does not itself perform those analyses and is partly PCA-specific despite broader documentation.

Static analysis

No suspicious patterns detected.