Back to skill

Security audit

Microbiome Diversity Reporter

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its microbiome reporting purpose, but its generated HTML can include unescaped user-supplied sample names and its file/dependency boundaries are under-scoped.

Install only in an isolated Python environment, review or pin dependencies before use, and avoid opening or sharing generated HTML reports from untrusted OTU/ASV inputs until sample names and other input-derived fields are escaped. Keep output paths inside a workspace directory to avoid accidental overwrite of unrelated files.

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)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/main.py:612
Finding
Unescaped Sample Identifiers Enable Stored HTML Injection<![CDATA[ ## Vulnerability Details **File Location**: `scripts/main.py:612-617` **Related Input Source**: `scripts/main.py:650-654` **Vulnerability Type**: Stored HTML injection through unescaped input-derived content **Risk Level**: Medium ### Complete Code Snippet Input-derived sample identifiers are loaded directly from the first column of the supplied TSV file: ```python def load_otu_table(path: str) -> pd.DataFrame: """Load OTU table""" df = pd.read_csv(path, sep='\t', index_col=0, comment='#') # Transpose so that samples are rows and OTUs are columns if df.shape[0] > df.shape[1]: df = df.T return df ``` Those identifiers are subsequently inserted into the generated HTML without output encoding: ```python for sample, coords in pcoa['samples'].items(): html_content += f""" <tr> <td>{sample}</td> <td>{coords['PC1']:.3f}</td> <td>{coords['PC2']:.3f}</td> <td>{coords['PC3']:.3f}</td> </tr> """ ``` ### Technical Analysis The sample identifier is controlled by the contents of the user-supplied OTU/ASV table. It propagates from the DataFrame index into an HTML f-string without contextual escaping or sanitization. HTML generation must encode untrusted text before placing it into an HTML document. Because the value is inserted directly between `<td>` tags, an identifier containing HTML elements or event handlers is interpreted as markup rather than displayed as plain text. For example, a sample identifier could contain: ```html <img src=x onerror=alert(document.domain)> ``` The generated report would preserve that value as an active HTML element. When the report is opened in a browser, its event handler can execute in the report's browser context. ### Attack Path 1. An attacker creates or modifies an OTU/ASV TSV file. 2. The attacker places an HTML or JavaScript payload in a sample identifier. 3. A user runs the tool with the mali ...[truncated 1097 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Encode every input-derived value before inserting it into HTML. At minimum, apply `html.escape()` with quote escaping: ```python import html for sample, coords in pcoa['samples'].items(): safe_sample = html.escape(str(sample), quote=True) html_content += f""" <tr> <td>{safe_sample}</td> <td>{coords['PC1']:.3f}</td> <td>{coords['PC2']:.3f}</td> <td>{coords['PC3']:.3f}</td> </tr> """ ``` A stronger long-term approach is to use an HTML template engine with automatic escaping enabled. All values derived from OTU tables, metadata, labels, column names, and future user-configurable fields should be treated as untrusted. Add regression tests that generate reports using identifiers containing: - `<script>` elements. - Event-handler attributes such as `onerror`. - Quotes and angle brackets. - Encoded and nested markup. The tests should verify that the generated report contains encoded text such as `&lt;` and does not contain executable attacker-supplied markup. ]]>

T08 · Insecure Dependencies

Note
Location
requirements.txt:1
Finding
Unpinned and Inconsistent Third-Party Dependency Declaration<![CDATA[ ## Vulnerability Details **File Location**: `requirements.txt:1-7` **Related Documentation**: `SKILL.md:20-27`, `SKILL.md:232` **Vulnerability Type**: Unsafe dependency resolution and package-identity inconsistency **Risk Level**: Low ### Complete Code Snippet The requirements file declares all dependencies without version or integrity constraints: ```text matplotlib numpy pandas plotly scipy seaborn skbio ``` The skill documentation describes the expected dependency differently: ```text - Python 3.8+ - numpy - pandas - scipy - scikit-bio - matplotlib - seaborn - plotly (for interactive charts) ``` It directs users to install the requirements without further verification: ```text pip install -r requirements.txt ``` ### Technical Analysis Every dependency is unconstrained, so installation resolves to whichever versions are available from the configured package index at installation time. This prevents reproducible dependency resolution and can introduce newly compromised, incompatible, or vulnerable releases without any change to the audited project. There is also a package-identity inconsistency: the documentation identifies the dependency as `scikit-bio`, while `requirements.txt` requests `skbio`. Package-name discrepancies create dependency-confusion or unintended-package risks because users may install a distribution other than the one reviewed or intended by the project. No malicious dependency payload was identified in the project itself. The vulnerability is the uncontrolled and ambiguous dependency acquisition process. ### Attack Path 1. A user follows the documented setup instruction and runs `pip install -r requirements.txt`. 2. The package installer queries the user's configured package index or mirror. 3. Because versions and artifact hashes are absent, the resolver accepts currently available matching distributions. 4. The inconsistent `skbio` package name may resolve differently from the documented `scikit-bio` distributi ...[truncated 1170 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Confirm the intended canonical distribution name and make `requirements.txt` consistent with the documented `scikit-bio` dependency. 2. Pin every direct dependency to a reviewed version rather than allowing unrestricted resolution. 3. Generate and commit a lock file that includes transitive dependencies. 4. Use hash-verified installation, for example with requirements entries generated using `pip-compile --generate-hashes` and installation through: ```bash pip install --require-hashes -r requirements.txt ``` 5. Install only from approved package indexes or an internally controlled mirror. 6. Add automated dependency vulnerability and license scanning to the release process. 7. Review and update pinned dependencies on a controlled schedule, testing the diversity calculations before accepting updates. ]]>
Vulnerability Patterns
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (13)

Lp3

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding
The skill advertises executable workflows that read inputs and write output files, but it does not declare any explicit tool scope such as permissions or allowed-tools. That mismatch weakens containment and reviewability, because an agent may invoke file-writing behavior without a clearly bounded policy surface, increasing the chance of unintended file modification or broader filesystem access.

Vague Triggers

Medium
Confidence
91% confidence
Finding
The activation guidance says to use the skill for general academic writing tasks, which is broader than the stated purpose of interpreting microbiome alpha and beta diversity metrics. Over-broad routing can cause the skill to be selected in unrelated contexts, where its instructions to run packaged scripts and handle files may be applied to inappropriate inputs, increasing the risk of misuse, data handling mistakes, or unsafe execution paths.

Unpinned Dependencies

Low
Category
Supply Chain
Content
matplotlib
numpy
pandas
plotly
Confidence
98% confidence
Finding
The dependency 'matplotlib' is specified without any version constraint, making builds non-reproducible and allowing installation of unexpected or newly vulnerable releases. While this is a supply-chain hygiene issue rather than an immediately exploitable flaw in the file itself, it increases risk because future environments may resolve to unsafe versions.

Unpinned Dependencies

Low
Category
Supply Chain
Content
matplotlib
numpy
pandas
plotly
scipy
Confidence
99% confidence
Finding
The dependency 'numpy' is unpinned, so different installations may pull different versions, including releases with known security advisories. This weakens supply-chain control and makes it impossible to verify whether deployed environments are using a safe version.

Unverifiable Dependency: numpy has 16 known advisory(ies) (CVE-2014-1859 (Numpy arbitrary file write via symlink attack); CVE-2021-41495 (NumPy NULL Pointer Dereference); CVE-2021-33430 (NumPy Buffer Overflow (Disputed)) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
99% confidence
Finding
Because 'numpy' is unpinned and has known advisories across some releases, the manifest does not provide enough information to determine whether deployments are affected. This is dangerous because a vulnerable version could be installed silently, especially in fresh or rebuilt environments.

Unpinned Dependencies

Low
Category
Supply Chain
Content
matplotlib
numpy
pandas
plotly
scipy
seaborn
Confidence
98% confidence
Finding
The dependency 'pandas' is listed without a version, which creates uncertainty about which code will actually be installed in different environments. That increases exposure to accidental adoption of vulnerable or incompatible releases and undermines reproducibility.

Unverifiable Dependency: pandas has 1 known advisory(ies) (CVE-2020-13091 (** DISPUTED ** pandas through 1.0.3 can unserialize and execute commands from an)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
98% confidence
Finding
The unpinned 'pandas' dependency cannot be verified against its known advisory history, so there is no assurance that installed environments are safe. This creates avoidable uncertainty in a package that may process untrusted data inputs in analysis workflows.

Unpinned Dependencies

Low
Category
Supply Chain
Content
matplotlib
numpy
pandas
plotly
scipy
seaborn
skbio
Confidence
97% confidence
Finding
The dependency 'plotly' is unpinned, which permits uncontrolled version drift across environments. This can introduce vulnerable or breaking releases into the skill without any manifest change.

Unpinned Dependencies

Low
Category
Supply Chain
Content
numpy
pandas
plotly
scipy
seaborn
skbio
Confidence
99% confidence
Finding
The dependency 'scipy' is not version-pinned, so installations may resolve to arbitrary versions, including ones with known advisories. This is especially relevant because scipy has historical security issues, making lack of version control a real supply-chain concern.

Unverifiable Dependency: scipy has 4 known advisory(ies) (CVE-2013-4251 (SciPy creates insecure temporary directories); CVE-2013-4251 (The scipy.weave component in SciPy before 0.12.1 creates insecure temporary dire); CVE-2023-25399 (A refcounting issue which leads to potential memory leak was discovered in scipy) +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
99% confidence
Finding
The manifest leaves 'scipy' unpinned despite known advisories in some versions, so the actual security posture of an installation cannot be verified. This is a classic dependency-management weakness that can lead to accidental deployment of vulnerable code.

Unpinned Dependencies

Low
Category
Supply Chain
Content
pandas
plotly
scipy
seaborn
skbio
Confidence
97% confidence
Finding
The dependency 'seaborn' is unpinned, making installations non-deterministic and weakening dependency governance. Even if no advisory is cited here, future vulnerable releases could be pulled automatically.

Unpinned Dependencies

Low
Category
Supply Chain
Content
plotly
scipy
seaborn
skbio
Confidence
97% confidence
Finding
The dependency 'skbio' is unpinned, allowing uncontrolled resolution to different versions over time. This creates supply-chain uncertainty and can expose deployments to vulnerable or untested releases.

Natural-Language Policy Violations

Low
Confidence
91% confidence
Finding
This file contains fixed natural-language report content with multiple hard-coded English phrases and no mechanism for users to choose another language or locale. The policy category applies to all file types, and a fixed output language without opt-in can violate language/locale policy expectations.

Static analysis

No suspicious patterns detected.