Back to skill

Security audit

Reagent Substitute Scout

Security checks for vulnerabilities and agentic risk

Overview

This appears to be a real reagent-search skill, but it needs review because its output option can overwrite arbitrary writable files and its install dependencies are not pinned.

Install only in a dedicated virtual environment, pin and audit dependencies before use, and keep --output restricted to a new file inside the workspace. Do not use this with confidential reagent names, CAS numbers, or research programs unless PubMed/PubChem network egress is approved.

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
requirements.txt:1
Finding

Unpinned Third-Party Dependencies Create Supply-Chain Risk

Content
View full analysis

Vulnerability Details

File Location: requirements.txt:1-9; installation instructions at SKILL.md:236 and SKILL.md:293
Vulnerability Type: Unpinned dependency installation
Risk Level: Medium

Vulnerable Code

text
biopython
dataclasses
numpy
pandas
pydantic
rdkit
requests
rich
tabulate

The documented installation command resolves these unconstrained dependencies:

bash
pip install -r requirements.txt

Technical Analysis

Every dependency is specified without an exact version or integrity hash. Each installation can therefore resolve a different release from the configured package index. This prevents reproducible security review and permits newly published, compromised, or unexpectedly incompatible releases to be selected without any project change.

Python package installation may execute package build logic with the privileges of the user running pip. Several declared packages are not imported by the executable, which unnecessarily expands the number of upstream projects and transitive dependencies that must remain trustworthy. The dataclasses backport is also unnecessary under the documented Python 3.8-or-newer requirement.

No evidence establishes that any currently resolved package is malicious. The confirmed issue is the absence of version and integrity controls around executable third-party components.

Attack Path

  1. A user or automation system follows the installation instructions in SKILL.md.
  2. pip resolves the unconstrained names against its configured package index.
  3. An upstream package account, release, distribution artifact, or transitive dependency is compromised, or an unsafe future release becomes the selected version.
  4. The malicious or unsafe artifact is downloaded because no reviewed version or hash is enforced.
  5. Package build or installation logic executes, or malicious code runs when the installed module is imported.

...[truncated 569 chars]

Remediation
View remediation

Remediation Suggestions

  1. Remove dependencies that are not used by scripts/main.py.
  2. Remove the dataclasses backport when Python 3.8 or newer is required.
  3. Pin every direct and transitive dependency to a reviewed version through a generated lock file.
  4. Record cryptographic hashes for every approved distribution and install with pip --require-hashes.
  5. Prefer binary wheels from a controlled index and disable unexpected source builds where practical.
  6. Run dependency vulnerability and license scanning in CI.
  7. Use a dedicated virtual environment and avoid installing packages with administrative privileges.
  8. Establish a controlled update process that reviews and tests dependency changes before refreshing the lock file.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/main.py:680
Finding

Caller-Controlled Output Path Permits Arbitrary File Overwrite

Content
View full analysis

Vulnerability Details

File Location: scripts/main.py:680-683 and scripts/main.py:730-733
Vulnerability Type: Unrestricted filesystem write and symlink-following overwrite
Risk Level: Medium

Vulnerable Code

python
parser.add_argument(
    "--output", "-o",
    help="Output file path"
)
python
# Output results
if args.output:
    with open(args.output, 'w', encoding='utf-8') as f:
        f.write(output)
    print(f"Results have been saved to: {args.output}")
else:
    print(output)

Technical Analysis

The --output argument accepts an arbitrary path. The value is passed directly to open(..., 'w') without canonicalization, workspace containment, overwrite confirmation, exclusive creation, or symlink rejection.

Opening a destination in w mode creates the file if absent and truncates it if it already exists. Python also follows symbolic links by default. Consequently, any file writable by the executing account can be replaced with generated report content. Relative traversal components such as ../ and absolute paths are not rejected.

The vulnerability does not independently elevate operating-system privileges: filesystem permissions still apply. It nevertheless violates least-privilege output handling and conflicts with the workspace restriction identified in the project security checklist.

Attack Path

  1. An attacker influences the CLI arguments supplied by a user, agent, workflow, or wrapper script.
  2. The attacker sets --output to a sensitive file writable by the executing account, either directly or through a symbolic link.
  3. The program completes its reagent search and enters the output branch.
  4. open(args.output, 'w', encoding='utf-8') follows the path and truncates the destination.
  5. The generated report is written over the original contents.
  6. A subsequent application or user operation consumes the corrupted file, causing data loss o ...[truncated 543 chars]
Remediation
View remediation

Remediation Suggestions

  1. Define a dedicated output directory beneath the project workspace or another explicitly approved root.
  2. Resolve both the approved root and requested destination with pathlib.Path.resolve() and verify that the destination remains beneath that root.
  3. Reject absolute paths, traversal outside the approved directory, and symbolic-link destinations.
  4. Create new files exclusively by default, such as with mode x, so existing files are not silently truncated.
  5. Require an explicit, separately validated overwrite option before replacing an existing regular file.
  6. For robust symlink protection on supported platforms, open files using low-level flags such as O_NOFOLLOW and O_EXCL, then write through the returned descriptor.
  7. Run the skill with a minimally privileged account and restrict filesystem access at the sandbox or container level.
  8. Add tests covering absolute paths, ../ traversal, existing files, symlinks, and destinations outside the approved workspace.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (21)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill advertises executable Python code with network, file read, and file write capabilities, but it does not declare any explicit tool scope such as permissions or allowed-tools. That omission weakens policy enforcement and reviewability because an orchestrator or reviewer cannot easily constrain what the skill is expected to access, increasing the risk of unintended external calls or filesystem use when the skill is invoked.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
83% confidence
Finding

The activation guidance uses broad phrases such as evidence insight tasks, documented fallback paths, and reproducible output, which are generic enough to match many unrelated research or analysis requests. Over-broad triggers can cause unintended activation of a networked, code-executing skill in contexts where it is unnecessary, expanding attack surface and creating opportunities for prompt-routing mistakes or misuse.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The manifest and module docstring emphasize validated alternatives derived from literature citation data. However, the implementation also sources candidates from a built-in offline database and PubChem similarity/identity searches, then combines those signals into scoring, so the actual behavior is broader than the stated literature-citation-based scope.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

User-supplied reagent names are sent to PubMed without any clear user-facing disclosure or opt-in at the point of use. In a chemistry workflow, reagent names, target compounds, or project-specific terminology can reveal sensitive research activity, so automatic transmission to external services can leak confidential metadata even if the requests are otherwise legitimate.

Content

No source excerpt is available for this finding.

Tainted flow: 'summary_params' from requests.get (line 135, network input) → requests.get (network output)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/main.py (reported line 143)May include surrounding context.

python
if self.api_key:
                    summary_params["api_key"] = self.api_key
                
                summary_response = requests.get(
                    f"{self.BASE_URL}/esummary.fcgi", 
                    params=summary_params,
                    timeout=30

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The code sends user-provided reagent names or CAS identifiers to PubChem automatically, which can disclose proprietary compound interests or research programs to a third party. In this skill's chemistry context, those identifiers may be commercially sensitive, making the privacy risk more significant than in a generic public-search tool.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
98% confidence
Finding

The dependency manifest leaves Biopython unpinned, which makes builds non-reproducible and can cause installation of different versions over time, including newly introduced vulnerable releases. In this skill's scientific/data-processing context, Biopython may parse structured biological data, so version drift can quietly introduce security or integrity issues without code changes.

Content

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

text
biopython
dataclasses
numpy
pandas

Unverifiable Dependency: biopython has 2 known advisory(ies) (CVE-2025-68463 (Biopython is vulnerable to doctype XML external entity (XXE) injection through B); CVE-2025-68463 (Biopython is vulnerable to doctype XML external entity (XXE) injection through B)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
97% confidence
Finding

Biopython has known advisories, but because no version is pinned, it is impossible to verify whether deployment will install a fixed or vulnerable release. This is especially relevant in scientific tooling where parsers may handle complex file formats, and the cited XXE issue could become exploitable if XML-containing biological data is processed.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
93% confidence
Finding

The dataclasses package is unpinned, so dependency resolution is not deterministic and may pull unexpected versions or supply-chain substitutions depending on environment. This is lower risk than code-level flaws, but it still weakens build integrity and repeatability.

Content

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

text
biopython
dataclasses
numpy
pandas
pydantic

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
98% confidence
Finding

NumPy is unpinned, which means the environment may install arbitrary future or older versions with different security and memory-safety characteristics. Since NumPy is a foundational package used broadly by other components, an unsafe or incompatible version can expand blast radius across the skill.

Content

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

text
biopython
dataclasses
numpy
pandas
pydantic
rdkit

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

NumPy has multiple historical advisories, and the unpinned manifest prevents verification that only patched releases are used. Although exploitability depends on how NumPy is exercised, uncertainty around a foundational native-extension dependency is a meaningful security risk.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
98% confidence
Finding

Pandas is unpinned, creating a reproducibility and supply-chain risk because installations may resolve to different versions over time. In a literature/reagent analysis skill, data ingestion and parsing behavior matters, so version drift can affect both security posture and result integrity.

Content

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

text
biopython
dataclasses
numpy
pandas
pydantic
rdkit
requests

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 advisory history, and without version pinning there is no assurance the installed version is unaffected. In this context the cited issue appears more conditional and lower confidence, but the inability to verify version safety remains a real dependency-management weakness.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
98% confidence
Finding

Pydantic is unpinned, allowing installation of versions with differing validation behavior or known vulnerabilities. Because Pydantic often mediates untrusted input validation, this can directly affect robustness and resilience against malformed or malicious data.

Content

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

text
dataclasses
numpy
pandas
pydantic
rdkit
requests
rich

Unverifiable Dependency: pydantic has 4 known advisory(ies) (CVE-2021-29510 (Use of "infinity" as an input to datetime and date fields causes infinite loop i); CVE-2024-3772 (Pydantic regular expression denial of service); CVE-2021-29510 (Pydantic is a data validation and settings management using Python type hinting.) +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
95% confidence
Finding

Pydantic has several known advisories, and the unpinned requirement makes it impossible to determine whether the runtime will use a patched version. Because Pydantic may validate user- or network-supplied data, issues like ReDoS or parser edge cases can be more reachable in practice.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
91% confidence
Finding

RDKit is unpinned, which weakens reproducibility and may introduce unexpected behavior or vulnerabilities through future package changes. Given this chemistry-oriented skill likely processes molecular data, parser/library changes can affect both security and analytical correctness.

Content

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

text
numpy
pandas
pydantic
rdkit
requests
rich
tabulate

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
99% confidence
Finding

Requests is unpinned, which is more concerning because it is a network-facing library commonly exposed to URL parsing, redirects, proxies, and credential-handling issues. In a skill that likely fetches literature or citation data, an unsafe requests version can materially increase exposure to remote attack paths.

Content

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

text
pandas
pydantic
rdkit
requests
rich
tabulate

Unverifiable Dependency: requests has 16 known advisory(ies) (CVE-2014-1830 (Exposure of Sensitive Information to an Unauthorized Actor in Requests); CVE-2024-47081 (Requests vulnerable to .netrc credentials leak via malicious URLs); CVE-2024-35195 (Requests `Session` object does not verify requests after making first request wi) +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
98% confidence
Finding

Requests has numerous advisories affecting credential handling, redirect behavior, and HTTP security, but the manifest does not pin a version, so a vulnerable release may be installed unknowingly. In a skill that likely retrieves literature or citation data over the network, this materially raises the chance of remote exploitation or sensitive information leakage.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
90% confidence
Finding

Rich is unpinned, creating nondeterministic dependency resolution and possible exposure to future vulnerable releases. While primarily a presentation library and therefore lower risk than network or parser dependencies, it still contributes to overall supply-chain uncertainty.

Content

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

text
pydantic
rdkit
requests
rich
tabulate

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
90% confidence
Finding

Tabulate is unpinned, which permits uncontrolled version drift and reduces build reproducibility. Its role appears limited to output formatting, so the direct security impact is lower, but it remains a supply-chain hygiene issue.

Content

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

text
rdkit
requests
rich
tabulate

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
78% confidence
Finding

The configuration and class-level documentation imply an overall score driven by citation, recency, and similarity weighting. In practice, total_score uses fixed constants, ignores recency entirely, and _score_candidates assigns coarse reliability buckets rather than applying the declared configuration, which contradicts the documented intent of configurable scoring behavior.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.