Back to skill

Security audit

Spatial Transcriptomics Mapper

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent local analysis tool, but it has review-worthy file-output and report-generation weaknesses when processing untrusted datasets.

Review before installing. Use this only in an isolated Python environment as an unprivileged user, avoid untrusted datasets or suspicious gene identifiers, keep output paths in a disposable workspace, and do not open generated HTML reports from untrusted inputs until gene names and filenames are escaped/sanitized. The publisher should replace 'pil' with Pillow, pin dependencies, and add output path containment checks.

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

Warning
Location
scripts/main.py:728
Finding

Stored HTML Injection Through Unescaped Dataset-Controlled Gene Names

Content
View full analysis
{gene}
{gene} expression
Expression: {stats.get('total_counts', 'N/A')} counts | Detection rate: {stats.get('detection_rate', 0):.1%}
""" ``` The same untrusted value is also inserted into the statistics table: ```python for gene in genes[:10]: if gene in self.gene_names: stats = self.get_spatial_stats(gene) html_content += f""" {gene} {stats.get('total_counts', 0):,} {stats.get('mean_expression', 0):.4f} {stats.get('max_expression', 0):.1f} {stats.get('detection_rate', 0):.1%} """ ``` ### Technical Analysis Gene names are obtained from the loaded transcriptomics dataset and can therefore be controlled by the creator of that dataset. `generate_report()` interpolates these values directly into HTML text nodes and quoted HTML attributes without context-appropriate escaping. A malicious gene name containing HTML syntax, such as: ```text "> ``` can terminate the existing attribute and inject a new active HTML element. The resulting payload is stored in `spatial_report.html` and executes when a user opens the report in a browser. The vulnerability affects both the gene card and statistics table. It does not require command execution on the host; exploitation occurs in the browser co ...[truncated 1207 chars]
Remediation
View remediation
{safe_gene}
{safe_gene} expression """ ``` 3. Prefer a maintained template engine with automatic escaping, such as Jinja2 with autoescaping enabled, rather than manually concatenating HTML. 4. Validate gene identifiers against an expected character set where practical. This should supplement, not replace, output encoding. 5. Generate image filenames independently from display names, such as with a random identifier or validated slug. 6. Add tests using gene names containing quotation marks, angle brackets, ampersands, and event-handler payloads. Verify that the generated report contains encoded text rather than executable markup. 7. Consider adding a restrictive Content Security Policy to the generated report as defense in depth, while retaining proper HTML escaping as the primary fix. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/main.py:674
Finding

Output Directory Escape Through Dataset-Controlled Gene Filenames

Content
View full analysis
/../../target_spatial_map.png ``` When Matplotlib saves the plot, the operating system resolves the traversal components and writes outside the configured output directory. The fixed `_spatial_map.png` suffix limits the resulting filename but does not prevent directory escape or overwrite of an existing writable file with that suffix. ### Attack Path 1. An attacker creates a supported dataset whose gene list contains a path-like identifier such as `../../target`. 2. The victim places the dataset in an accessible directory and runs the mapper. 3. The victim requests that exact gene and enables report generation. 4. The gene passes the membership check because it exists in `self.gene_names`. 5. `generate_report()` joins the untrusted identifier directly to `self.output_dir`. 6. `plt.savefig()` resolve ...[truncated 874 chars]
Remediation
View remediation
str: value = re.sub(r"[^A-Za-z0-9._-]+", "_", value) value = value.lstrip(".") if not value: raise ValueError("Gene name cannot produce an empty filename") return value[:120] ``` 3. Resolve and verify every generated destination before writing: ```python output_root = self.output_dir.resolve() safe_gene = safe_filename(gene) plot_path = (output_root / f"{safe_gene}_spatial_map.png").resolve() if output_root not in plot_path.parents: raise ValueError("Generated plot path escapes the output directory") ``` 4. Apply equivalent containment validation to `output_file` in `generate_report()`, particularly because the method is part of the public Python API. 5. Avoid silently overwriting existing files. Use exclusive creation, unique output identifiers, or explicitly require an overwrite option. 6. Add regression tests for gene identifiers containing `../`, `..\`, absolute path syntax, leading dots, path separators, Unicode separator-like characters, and unusually long values. ]]>

T08 · Insecure Dependencies

Note
Location
requirements.txt:1
Finding

Unpinned and Incorrectly Named Third-Party Dependencies

Content
View full analysis
Remediation
View remediation
--hash=sha256: ``` 4. Maintain separate base and optional dependency groups. For example, isolate Xenium-only or advanced visualization dependencies rather than installing all packages unconditionally. 5. Run dependency vulnerability scanning in continuous integration using tools such as `pip-audit` or an equivalent software-composition-analysis system. 6. Install dependencies in an isolated virtual environment as an unprivileged user. 7. Configure trusted package indexes explicitly and prevent fallback to unintended indexes when private package repositories are used. 8. Test a clean installation from the locked dependency set and update `SKILL.md` so its installation instructions exactly match `requirements.txt`. ]]>
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
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (20)

Possible Typosquatting: 'pil' resembles popular package 'pip'

High
Category
Supply Chain
Confidence
99% confidence
Finding

The package name 'pil' is highly suspicious because the commonly used imaging library is Pillow, while PIL is obsolete and not the standard package to declare in modern requirements. This creates a realistic typosquatting or wrong-package risk that can result in installation of unintended code from the package index.

Content

No source excerpt is available for this finding.

Possible Typosquatting: 'scanpy' resembles popular package 'scrapy'

High
Category
Supply Chain
Confidence
70% confidence
Finding

Package name closely resembles a popular package, suggesting possible typosquatting. Attackers publish malicious packages with similar names to trick developers into installing them.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill advertises executable scripts and output generation but does not declare any explicit tool scope such as allowed tools or permissions. That creates a policy gap where an agent may infer it can perform file writes broadly, increasing the risk of unintended or unsafe filesystem actions beyond the expected workspace.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The top-level description is truncated and ambiguous, so the agent cannot reliably determine the exact task boundary for invocation. Ambiguous activation scope can cause the skill to be selected for adjacent biomedical or image-analysis tasks it was not designed to handle, which weakens safety gating and increases the chance of unsafe execution on inappropriate inputs.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The 'When to Use' section repeats the vague description and adds broad language like 'data analysis tasks' and 'reproducible output format,' which does not meaningfully constrain activation. An agent could invoke this skill for unrelated analysis jobs, causing unnecessary script execution, file access, or misuse of domain-specific code on unsafe or irrelevant inputs.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The help text and argument definitions claim support for '--min-count' filtering and '--crop' spatial cropping, creating an expectation that these options affect analysis behavior. In the rest of the file, neither argument is referenced, so the documented intent contradicts the actual implementation.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
94% confidence
Finding

The dependency list is unpinned, so installations may resolve to different versions over time, including newly introduced vulnerable or incompatible releases. In a data-processing skill that pulls in complex scientific packages, this increases supply-chain and reproducibility risk even if it is not an immediate exploit by itself.

Content

Scanner excerpt · requirements.txt (reported line 1)May include surrounding context.

text
h5py
matplotlib
numpy
pandas

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
94% confidence
Finding

The dependency list is unpinned, so installations may resolve to different versions over time, including newly introduced vulnerable or incompatible releases. In a data-processing skill that pulls in complex scientific packages, this increases supply-chain and reproducibility risk even if it is not an immediate exploit by itself.

Content

Scanner excerpt · requirements.txt (reported line 2)May include surrounding context.

text
h5py
matplotlib
numpy
pandas
pil

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
96% confidence
Finding

The dependency list is unpinned, so installations may resolve to different versions over time, including newly introduced vulnerable or incompatible releases. This is slightly more concerning here because numpy is a foundational package with a broad transitive impact across the environment.

Content

Scanner excerpt · requirements.txt (reported line 3)May include surrounding context.

text
h5py
matplotlib
numpy
pandas
pil
pyarrow

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
90% confidence
Finding

Numpy has known advisories, and because no version is pinned, it is impossible to verify whether deployment will install a fixed or affected release. In a skill that processes user-supplied scientific data, unverifiable package state weakens assurance and may expose the environment to known parser or memory-safety issues.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

The dependency list is unpinned, so installations may resolve to different versions over time, including newly introduced vulnerable or incompatible releases. For packages that may deserialize or parse complex data formats, version drift can expose the environment to avoidable known issues.

Content

Scanner excerpt · requirements.txt (reported line 4)May include surrounding context.

text
h5py
matplotlib
numpy
pandas
pil
pyarrow
scanpy

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
88% confidence
Finding

Pandas has at least one relevant advisory and the manifest does not specify a version, so the installed release could still be affected. Because data science workflows often read untrusted files and serialized data, leaving the version unspecified creates avoidable uncertainty around known security behavior.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
99% confidence
Finding

This dependency is unpinned and also appears to reference a suspicious package name, making the risk more than routine version drift. If the resolver installs an unexpected or malicious package named 'pil', the environment could execute attacker-controlled code during installation or import.

Content

Scanner excerpt · requirements.txt (reported line 5)May include surrounding context.

text
matplotlib
numpy
pandas
pil
pyarrow
scanpy
seaborn

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
96% confidence
Finding

The dependency list is unpinned, so installations may resolve to different versions over time, including vulnerable releases. This matters more for pyarrow because it handles complex binary and columnar data formats that have had security-relevant parsing issues.

Content

Scanner excerpt · requirements.txt (reported line 6)May include surrounding context.

text
numpy
pandas
pil
pyarrow
scanpy
seaborn
squidpy

Unverifiable Dependency: pyarrow has 9 known advisory(ies) (CVE-2023-47248 (PyArrow: Arbitrary code execution when loading a malicious data file); CVE-2019-12408 (Missing Initialization of Resource in Apache Arrow); CVE-2019-12410 (Missing Initialization of Resource in Apache Arrow) +6 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
95% confidence
Finding

PyArrow has had serious advisories, including issues related to loading malicious data files, and the unpinned manifest makes it impossible to confirm a safe version. Given this skill's domain of ingesting complex bioinformatics datasets, this context makes the risk more meaningful than a generic library mismatch.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
90% confidence
Finding

The dependency list is unpinned, so installations may resolve to different versions over time, creating supply-chain and reproducibility risk. In this case the package name likely refers to a legitimate scientific library, so the issue is mainly operational unless combined with a malicious mirror or future vulnerable release.

Content

Scanner excerpt · requirements.txt (reported line 7)May include surrounding context.

text
pandas
pil
pyarrow
scanpy
seaborn
squidpy
tifffile

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
94% confidence
Finding

The dependency list is unpinned, so installations may resolve to different versions over time, including newly introduced vulnerable or incompatible releases. While common in prototypes, this is still a security and integrity weakness in production or shared execution environments.

Content

Scanner excerpt · requirements.txt (reported line 8)May include surrounding context.

text
pil
pyarrow
scanpy
seaborn
squidpy
tifffile

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
94% confidence
Finding

The dependency list is unpinned, so installations may resolve to different versions over time, including newly introduced vulnerable or incompatible releases. Scientific stacks also bring many transitive dependencies, which amplifies the effect of unpinned top-level packages.

Content

Scanner excerpt · requirements.txt (reported line 9)May include surrounding context.

text
pyarrow
scanpy
seaborn
squidpy
tifffile

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
94% confidence
Finding

The dependency list is unpinned, so installations may resolve to different versions over time, including newly introduced vulnerable or incompatible releases. This is especially relevant for file-format processing libraries, where parser bugs may be version-specific.

Content

Scanner excerpt · requirements.txt (reported line 10)May include surrounding context.

text
scanpy
seaborn
squidpy
tifffile

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The manifest description is narrowly phrased as mapping Visium/Xenium data, which matches the plotting functionality but does not mention report generation. This code goes beyond direct mapping by producing an HTML analysis report and multiple saved artifacts, extending the skill into reporting/output publishing behavior.

Content

No source excerpt is available for this finding.