Back to skill

Security audit

Survival Curve Risk Table

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly does the advertised survival-chart work, but it exposes users to review-worthy risk by accepting pickle data files and installing ambiguous unpinned dependencies.

Install only in an isolated virtual environment as a non-privileged user. Do not open .pkl or .pickle datasets unless they come from a trusted source; prefer CSV, Excel, or SAS files. Before broad use, remove the pil dependency, pin reviewed package versions, and remove or gate pickle support.

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

Error
Location
scripts/main.py:193
Finding

Unsafe Deserialization of Untrusted Pickle Files

Content
View full analysis

Vulnerability Details

File Location: scripts/main.py, lines 193–194
Vulnerability Type: Unsafe Python pickle deserialization
Risk Level: High

Vulnerable Code

python
elif suffix in ['.pkl', '.pickle']:
    df = pd.read_pickle(file_path)

The Skill also advertises Python pickle files as supported input in SKILL.md, making this code path part of its documented workflow.

Technical Analysis

pandas.read_pickle() uses Python pickle deserialization. Pickle is not a data-only format: serialized objects may define reconstruction behavior that invokes arbitrary Python callables during loading. Consequently, validating only the filename suffix does not make an untrusted pickle safe.

The CLI permits a caller to select the input path through --input. When that path ends in .pkl or .pickle, load_data_from_file() passes it directly to pd.read_pickle() without establishing that the file came from a trusted source or isolating deserialization in a sandbox.

An attacker able to supply or influence the input file can therefore craft a pickle whose reconstruction instructions execute arbitrary local code before a valid DataFrame is returned. No separate command-injection flaw is required.

Attack Path

  1. An attacker creates a malicious pickle containing an object with attacker-controlled reconstruction behavior.
  2. The attacker supplies that file as survival data or convinces a user or Agent to process it.
  3. The Skill is invoked with a command such as:
    bash
    python scripts/main.py \
      --input malicious.pkl \
      --time-col time \
      --event-col event
    
  4. load_data_from_file() recognizes the .pkl suffix.
  5. The function calls pd.read_pickle(file_path).
  6. Python reconstructs the malicious object, executing the embedded callable with the privileges of the Skill process.

Impact Assessment

Successful exploitation provides arbitrary code execution under the operating-system identity running the Skil ...[truncated 433 chars]

Remediation
View remediation

Remediation Suggestions

  1. Remove .pkl and .pickle from the accepted input formats.
  2. Use non-executable data formats such as CSV or Parquet for survival datasets.
  3. Return an explicit error for pickle inputs:
    python
    elif suffix in {'.pkl', '.pickle'}:
        raise ValueError(
            "Pickle input is disabled because it can execute arbitrary code. "
            "Convert the dataset to CSV or Parquet."
        )
    
  4. Remove pickle support claims from SKILL.md and related documentation.
  5. If legacy pickle compatibility is unavoidable:
    • Accept only files generated and stored within a trusted administrative workflow.
    • Verify provenance and integrity using a trusted manifest or cryptographic hash.
    • Deserialize in a separate, disposable sandbox with no credentials, no network access, read-only input access, and a narrowly scoped output channel.
    • Do not treat restricted-unpickler implementations as a complete substitute for avoiding pickle.
  6. Add a regression test confirming that .pkl and .pickle inputs are rejected before deserialization.

T08 · Insecure Dependencies

Warning
Location
requirements.txt:1
Finding

Non-Reproducible and Ambiguous Dependency Installation

Content
View full analysis

Vulnerability Details

File Location: requirements.txt, lines 1–7
Vulnerability Type: Unpinned dependencies and unnecessary ambiguous pil package
Risk Level: Medium

Vulnerable Configuration

text
lifelines
matplotlib
numpy
pandas
pil
pillow
seaborn

The documented installation command in README.md and SKILL.md is:

bash
pip install -r requirements.txt

Technical Analysis

All dependencies are specified without versions or integrity hashes. Each installation can therefore resolve to different package releases, including releases published after the Skill was audited. This prevents reproducible installation and makes it difficult to verify that the executed dependency set is the reviewed one.

The list also declares both pil and pillow. The implementation uses:

python
from PIL import Image

Pillow is the maintained package that provides the PIL import namespace. A separate pil requirement is unnecessary and introduces an additional, ambiguous package-resolution surface. Installing an unnecessary similarly named package increases exposure to dependency confusion, namespace collisions, unexpected package behavior, or installation failure.

This audit did not establish that any currently resolved package version is malicious. The confirmed issue is the unsafe dependency specification and expanded supply-chain exposure.

Attack Path

  1. A user or automated Agent follows the documented installation instructions.
  2. Pip resolves every unpinned requirement against the configured package index at installation time.
  3. The unnecessary pil name is resolved in addition to the official pillow dependency.
  4. Pip downloads whatever versions and distributions currently satisfy those mutable names.
  5. Package installation or later imports execute dependency-controlled code in the environment.
  6. If a resolved release is compromised, malicious, or unexpectedly incompatible, it can affect the Skill before or duri ...[truncated 600 chars]
Remediation
View remediation

Remediation Suggestions

  1. Remove the pil requirement and retain only the maintained Pillow distribution.
  2. Pin every direct dependency to a reviewed version or tightly controlled compatible range.
  3. Generate a lock file containing resolved transitive dependencies and cryptographic hashes, for example with pip-tools.
  4. Install with hash enforcement:
    bash
    pip install --require-hashes -r requirements.lock
    
  5. Review packages against vulnerability advisories before updating the lock file.
  6. Perform dependency updates through a controlled process that includes tests for risk-count correctness, plotting behavior, and supported file readers.
  7. Install dependencies in an isolated virtual environment as a non-privileged user.
  8. Consider separating optional dependencies such as lifelines and Pillow into explicit extras so installations include only required components.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (22)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 27)May include surrounding context.

md
- `lifelines`: `unspecified`. Declared in `requirements.txt`.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 28)May include surrounding context.

md
- `lifelines`: `unspecified`. Declared in `requirements.txt`.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 29)May include surrounding context.

md
- `lifelines`: `unspecified`. Declared in `requirements.txt`.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 30)May include surrounding context.

md
- `lifelines`: `unspecified`. Declared in `requirements.txt`.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 31)May include surrounding context.

md
- `lifelines`: `unspecified`. Declared in `requirements.txt`.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 32)May include surrounding context.

md
- `lifelines`: `unspecified`. Declared in `requirements.txt`.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 33)May include surrounding context.

md
- `lifelines`: `unspecified`. Declared in `requirements.txt`.

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

High
Category
Supply Chain
Confidence
99% confidence
Finding

The package name 'pil' is a strong typosquatting or confusion risk because Python users commonly intend 'Pillow' for imaging support, while 'PIL' is an obsolete import namespace rather than the standard package to install. Installing an unintended package from the index can lead to arbitrary malicious code execution during package installation or at import time, making this especially dangerous in a build pipeline.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The skill documentation presents concrete capabilities including PDF/SVG/PowerPoint outputs and, elsewhere, support for importing existing KM plot images and many data formats. However, this file repeatedly identifies scripts/main.py as the sole implementation surface without showing any corroborating implementation details, while the command examples and audit commands are inconsistent and minimal. This creates an intent-code divergence risk because the documentation asserts specific functionality as if implemented, but the surrounding execution guidance does not substantiate those capabilities.

Content

No source excerpt is available for this finding.

Insecure deserialization: pandas.read_pickle()

Medium
Category
Dangerous Code Execution
Confidence
98% confidence
Finding

The code accepts user-supplied file paths and deserializes .pkl/.pickle files via pandas.read_pickle(), which uses Python pickle semantics and can execute attacker-controlled code during loading. In a CLI data-analysis skill, this is especially dangerous because users are encouraged to open external datasets, making malicious dataset files a realistic attack vector.

Content

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

python
elif suffix == '.sas7bdat':
            df = pd.read_sas(file_path)
        elif suffix in ['.pkl', '.pickle']:
            df = pd.read_pickle(file_path)
        else:
            raise ValueError(f"Unsupported file format: {suffix}")

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
98% confidence
Finding

The skill is documented throughout as operating on survival-analysis files and columns, but the audit-ready example uses --input with a narrative clinical text string. That directly conflicts with the stated workflow and input contract for structured survival data, making the inline documentation misleading about what the code is meant to process.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

The dependency 'lifelines' is unpinned, so installs are not reproducible and may silently pull in newer releases with breaking changes or newly introduced vulnerabilities. In a data-analysis skill this increases supply-chain uncertainty, though by itself it is typically a low-severity hygiene issue rather than an immediate exploit.

Content

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

text
lifelines
matplotlib
numpy
pandas

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

The dependency 'matplotlib' is unpinned, which allows different environments to resolve different versions and undermines reproducibility. This can expose the skill to accidental adoption of vulnerable or incompatible releases from the package index.

Content

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

text
lifelines
matplotlib
numpy
pandas
pil

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
98% confidence
Finding

The dependency 'numpy' is unpinned, and this is more concerning because the package has multiple historical advisories. Without a version pin, it is impossible to know whether deployments will install a safe release, creating avoidable supply-chain and reproducibility risk.

Content

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

text
lifelines
matplotlib
numpy
pandas
pil
pillow

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

Numpy has known historical advisories, and because the manifest does not pin a version, there is no way to verify whether deployed environments are affected. In a review-oriented data skill this is moderately dangerous because the package is foundational and widely imported, so a vulnerable version could affect many code paths.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
97% confidence
Finding

The dependency 'pandas' is unpinned, so builds may resolve to different versions over time. Because pandas has had security-related reports, leaving it unconstrained makes it hard to verify that deployments are consistently using a safe version.

Content

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

text
lifelines
matplotlib
numpy
pandas
pil
pillow
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
84% confidence
Finding

Pandas has at least one reported advisory, and without version pinning the environment may resolve to an affected release. The practical risk here is lower than for active exploit code in the repository, but it still represents unverifiable supply-chain exposure.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
99% confidence
Finding

The entry 'pil' is unpinned, but more importantly it is suspicious because modern Python imaging usage is normally provided by 'Pillow', not a package named 'pil'. Leaving this unpinned compounds the risk by allowing arbitrary current index resolution for a potentially unintended or typosquatted package.

Content

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

text
matplotlib
numpy
pandas
pil
pillow
seaborn

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
98% confidence
Finding

The dependency 'pillow' is unpinned, and image-processing libraries have a history of memory-safety and resource-consumption issues. In this skill context, that matters because image-related dependencies may process untrusted files or generated artifacts, so version drift increases exposure.

Content

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

text
numpy
pandas
pil
pillow
seaborn

Unverifiable Dependency: pillow has 16 known advisory(ies) (CVE-2016-2533 (Pillow buffer overflow in ImagingPcdDecode); CVE-2023-50447 (Arbitrary Code Execution in Pillow); CVE-2021-27922 (Pillow Uncontrolled Resource Consumption) +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
95% confidence
Finding

Pillow has multiple historical vulnerabilities, including issues relevant to processing crafted image files, and the manifest does not specify a safe version. Because this skill may generate or manipulate visual outputs, an affected Pillow release could increase risk if it ever handles untrusted image content.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
94% confidence
Finding

The dependency 'seaborn' is unpinned, making installations non-deterministic and weakening change control over the software supply chain. For an analytical workflow skill this primarily affects reproducibility and can indirectly introduce vulnerable transitive dependencies.

Content

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

text
pandas
pil
pillow
seaborn

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
97% confidence
Finding

The generate_risk_table docstring documents a show_events option, and the CLI exposes --show-events at L609-L610 before passing it into generate_risk_table at L677-L680. However, inside generate_risk_table and its downstream helpers, only censored counts are conditionally prepared and drawn; there is no logic to calculate or display event counts. This is an intent/documentation mismatch rather than a low-level bug because the exposed interface advertises behavior the code does not perform.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.