Back to skill

Security audit

Heatmap Beautifier

Security checks for vulnerabilities and agentic risk

Overview

This skill is a local heatmap visualization helper with some reliability and documentation problems, but no evidence of hidden access, persistence, credential handling, exfiltration, or destructive behavior.

Install only in an isolated Python environment, use reviewed or pinned dependency versions, and treat the bundled audit/changelog claims as unreliable until the script is fixed. Expect the documented demo and metadata options to fail unless the implementation is updated, and avoid returning raw tracebacks from this tool to untrusted users.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/main.py:86
Finding

Broad Exception Handling Conceals Unexpected CSV Processing Failures

Content
View full analysis

Vulnerability Details

File Location: scripts/main.py, lines 86-92
Vulnerability Type: Broad exception handling
Risk Level: Medium

Vulnerable Code

python
# Support multiple separators
try:
    df = pd.read_csv(data_path, index_col=0)
except:
    try:
        df = pd.read_csv(data_path, index_col=0, sep='\t')
    except:
        df = pd.read_csv(data_path, index_col=0, sep=';')

Technical Analysis

Both bare except clauses catch every exception derived from BaseException, rather than only expected CSV parsing and decoding failures. This includes exceptions unrelated to delimiter detection, such as KeyboardInterrupt and SystemExit.

As a result, unexpected failures during the first two parsing attempts are incorrectly interpreted as delimiter problems. The code then continues processing the same input under different assumptions, which can conceal the original failure, produce misleading diagnostics, and interfere with reliable termination.

The behavior also contradicts SKILL.md, which claims that these clauses have been restricted to pd.errors.ParserError, UnicodeDecodeError, and ValueError.

Attack Path

  1. An attacker or untrusted user supplies a malformed or resource-intensive CSV file.
  2. pd.read_csv raises an exception during parsing or decoding.
  3. The bare handler suppresses the original exception and retries the input with a tab delimiter.
  4. If another exception occurs, it is suppressed again and the file is retried with a semicolon delimiter.
  5. The application may produce a misleading result or report only the final failure, concealing the actual cause.

Impact Assessment

This issue does not directly grant additional system privileges or arbitrary code execution. Its scope is limited to the heatmap process and data being processed. It can nevertheless undermine availability, diagnostic integrity, and output correctness when untrusted files a ...[truncated 12 chars]

Remediation
View remediation

Remediation Suggestions

Replace bare handlers with narrowly scoped exception types and preserve unexpected exceptions:

python
parse_errors = (
    pd.errors.ParserError,
    UnicodeDecodeError,
    ValueError,
)

try:
    df = pd.read_csv(data_path, index_col=0)
except parse_errors:
    try:
        df = pd.read_csv(data_path, index_col=0, sep='\t')
    except parse_errors:
        df = pd.read_csv(data_path, index_col=0, sep=';')

Additional hardening should include:

  • Record which delimiter was selected.
  • Reject empty matrices and matrices with no numeric values.
  • Impose documented file-size, row-count, and column-count limits before rendering.
  • Add tests confirming that unexpected exceptions propagate rather than being treated as parsing failures.
  • Update the documentation only after the implementation and tests match the stated behavior.

T09 · Insecure Skill Coding Practices

Note
Location
scripts/main.py:506
Finding

Uncaught Top-Level Errors Can Expose Local Paths and Internal Diagnostics

Content
View full analysis

Vulnerability Details

File Location: scripts/main.py, lines 506-510
Vulnerability Type: Unhandled exception and diagnostic information exposure
Risk Level: Low

Vulnerable Code

python
# Execute
hb = HeatmapBeautifier()
hb.create_heatmap(args.input, args.output, **kwargs)
print("✓ Done!")

Related documentation in SKILL.md, line 153, incorrectly claims:

text
FileNotFoundError and ValueError are caught in main() with
try/except (FileNotFoundError, ValueError) as e:
print(f'Error: {e}', file=sys.stderr); sys.exit(1)

Technical Analysis

The executable implementation does not place annotation loading or heatmap generation inside a top-level exception handler. A missing input file, malformed annotation JSON, invalid matrix, unsupported plotting value, or output failure can therefore emit a raw Python traceback.

Such tracebacks commonly contain local filesystem paths, module locations, call stacks, and library details. This information may assist reconnaissance when command output is exposed through an API, job runner, shared log, or agent response.

The discrepancy between the implementation and documentation is also operationally significant because callers may rely on the documented sanitized error behavior even though it is absent.

Attack Path

  1. An attacker or untrusted user provides a nonexistent input path, malformed annotation file, or invalid matrix.
  2. The corresponding exception propagates from load_annotations_from_json or create_heatmap.
  3. Python prints an uncaught traceback to standard error.
  4. A service, Agent, or automated job captures and returns that traceback.
  5. The attacker learns local paths, package locations, and implementation details visible in the diagnostic output.

Impact Assessment

No privilege escalation or code execution is established. The obtainable information is limited to details present in the traceback and exceptio ...[truncated 153 chars]

Remediation
View remediation

Remediation Suggestions

Wrap the complete operational path, including annotation loading, in narrow top-level exception handling:

python
import sys

try:
    if args.row_annot:
        row_annotations = load_annotations_from_json(args.row_annot)
    if args.col_annot:
        col_annotations = load_annotations_from_json(args.col_annot)

    hb = HeatmapBeautifier()
    hb.create_heatmap(args.input, args.output, **kwargs)
except (FileNotFoundError, ValueError, json.JSONDecodeError) as exc:
    print(f"Error: {exc}", file=sys.stderr)
    sys.exit(1)

In addition:

  • Avoid returning raw tracebacks to untrusted clients.
  • Send detailed tracebacks only to access-controlled diagnostic logs.
  • Sanitize exception messages if absolute paths should not be disclosed.
  • Return a consistent nonzero exit status on operational failure.
  • Add tests for missing files, malformed JSON, invalid matrices, and unwritable output destinations.

other

Note
Location
scripts/main.py:432
Finding

Documented CLI Features Are Absent from the Executable Implementation

Content
View full analysis

Vulnerability Details

File Location: scripts/main.py, lines 432-469
Vulnerability Type: Documentation and implementation integrity mismatch
Risk Level: Low

Affected Code

The parser requires an input file and does not define the documented --demo or --output-json options:

python
parser.add_argument('-i', '--input', required=True,
                   help='Input expression matrix (CSV format)')
parser.add_argument('-o', '--output', required=True,
                   help='Output image path')
parser.add_argument('-t', '--title', default='Gene Expression Heatmap',
                   help='Chart title')
parser.add_argument('--cmap', default='RdBu_r',
                   help='Color map (default: RdBu_r)')
parser.add_argument('--center', type=float, default=0,
                   help='Color center value (default: 0)')
parser.add_argument('--vmin', type=float,
                   help='Minimum value')
parser.add_argument('--vmax', type=float,
                   help='Maximum value')
parser.add_argument('--row-cluster', action='store_true',
                   help='Enable row clustering')
parser.add_argument('--col-cluster', action='store_true',
                   help='Enable column clustering')
parser.add_argument('--row-annot',
                   help='Row annotation JSON file path')
parser.add_argument('--col-annot',
                   help='Column annotation JSON file path')
parser.add_argument('--z-score', type=int, choices=[0, 1],
                   help='Z-score normalization (0=row, 1=col)')
parser.add_argument('--standard-scale', choices=['row', 'col'],
                   help='Normalization method (row or col)')
parser.add_argument('--figsize', nargs=2, type=float,
                   help='Figure size (width height)')
parser.add_argument('--dpi', type=int, default=300,
                   help='Output resolution (default: 300)')
parser.add_argument('--hide-row-
...[truncated 2172 chars]
Remediation
View remediation

Remediation Suggestions

Choose one consistent interface and enforce it across code, documentation, examples, and tests:

  • Implement --demo with synthetic data generation and make --input conditionally required.
  • Implement --output-json and write the documented gene order, sample order, and annotation-color metadata.
  • Add --data-path as an alias if it is intended to be public, or replace it with --input throughout SKILL.md.
  • Verify every documented command in continuous integration.
  • Check process exit status and output-file existence before an Agent reports successful completion.
  • Remove unsupported claims from POLISH_CHANGELOG.md and the bundled audit result until implementation is verified.

T08 · Insecure Dependencies

Note
Location
requirements.txt:1
Finding

Unpinned Third-Party Dependencies Permit Unreviewed Version Resolution

Content
View full analysis

Vulnerability Details

File Location: requirements.txt, lines 1-4
Vulnerability Type: Unpinned dependency versions
Risk Level: Low

Vulnerable Code

text
matplotlib
numpy
pandas
seaborn

SKILL.md also recommends installing SciPy, although SciPy is absent from requirements.txt:

text
pip install seaborn matplotlib scipy pandas numpy

Technical Analysis

The dependency manifest contains no version constraints or integrity hashes. Each installation can therefore resolve a different set of package versions from the configured package index.

Unpinned resolution increases exposure to compromised future releases, dependency-confusion conditions in misconfigured indexes, breaking API changes, and non-reproducible behavior. The inconsistency concerning SciPy further means that the documented and manifest-based environments may differ.

No malicious or typosquatted package name was found in the reviewed manifest. The risk arises from mutable dependency resolution rather than a confirmed malicious dependency.

Attack Path

  1. A deployment or Agent creates a fresh environment and installs requirements.txt.
  2. The package manager resolves the latest versions available from its configured index.
  3. A compromised release, compromised package index, or unsafe index configuration supplies an unreviewed package version.
  4. Installation or import executes package-controlled code with the permissions of the installer or heatmap process.
  5. Any resulting access is bounded by the privileges and credentials available to that process.

Impact Assessment

Exploitation is conditional on upstream compromise or unsafe package-index configuration. If it occurs, dependency code could execute with the same privileges as the installation or application process, potentially accessing its files, environment variables, network permissions, and output data. The current project itself contains n ...[truncated 47 chars]

Remediation
View remediation

Remediation Suggestions

Establish reproducible and reviewed dependency resolution:

  • Pin tested versions using exact constraints.
  • Include SciPy consistently if clustering requires it.
  • Generate a lock file from a trusted package index.
  • Use cryptographic hashes where supported, such as pip --require-hashes.
  • Configure an explicit trusted index and disable unintended supplemental indexes.
  • Run dependency vulnerability and license scanning in continuous integration.
  • Review and update pinned versions through a controlled maintenance process.
  • Build and install dependencies using a nonprivileged account in an isolated environment.
Vulnerability Patterns
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • 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 (8)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill advertises file-processing behavior but does not declare any explicit tool scope or permissions boundaries. In an agent environment, this can lead to overbroad file-read access, making it easier for the skill to consume unintended local files if the runtime grants default or inherited filesystem capabilities.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The audit JSON contains internally inconsistent security claims: multiple sections state that exception handling was fixed and verified, while the recommendations explicitly admit the underlying script may still retain a bare except and may not catch FileNotFoundError. In an agent pipeline, this can cause downstream systems to treat the skill as security-reviewed and deployable when the implementation may still suppress errors or fail unpredictably, undermining trust in the security gate.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
96% confidence
Finding

The dependency list specifies matplotlib without any version pin or constrained range, which makes builds non-reproducible and can cause the environment to resolve to a vulnerable or breaking release in the future. While this file alone does not prove exploitation, leaving dependencies unpinned increases supply-chain risk and weakens assurance over what code is actually installed.

Content

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

text
matplotlib
numpy
pandas
seaborn

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
98% confidence
Finding

NumPy is listed without a pinned version, so installations may pull different releases over time, including versions with known security issues or incompatible behavior. In a scientific Python stack, this is a common but still real supply-chain hygiene weakness rather than direct malicious logic.

Content

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

text
matplotlib
numpy
pandas
seaborn

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

The manifest does not pin NumPy, and NumPy has multiple published advisories across historical releases, so it is impossible to determine from this file whether a vulnerable version would be installed. The danger is not that the file directly invokes the vulnerable behavior, but that supply-chain ambiguity can silently introduce an affected release into the runtime environment.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
97% confidence
Finding

Pandas is unpinned, which means the installed package version is not controlled and may drift to a release with vulnerabilities or unexpected behavior. This is particularly relevant because pandas has had security-relevant advisories, so the absence of version control prevents verifying exposure.

Content

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

text
matplotlib
numpy
pandas
seaborn

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

Because pandas is unpinned and has at least one known advisory in prior releases, the actual security posture of deployments cannot be verified from this requirements file. This creates avoidable uncertainty in environments that may process external data, even if the skill’s stated purpose is heatmap beautification rather than risky deserialization workflows.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
96% confidence
Finding

Seaborn is also left unpinned, creating the same reproducibility and supply-chain uncertainty risk as the other dependencies. Although this is a low-severity issue, it still reduces confidence in the security and stability of the installed environment.

Content

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

text
matplotlib
numpy
pandas
seaborn

Static analysis

No suspicious patterns detected.