Back to skill

Security audit

Data Vault

Security checks for vulnerabilities and agentic risk

Overview

This skill is a coherent local data-store tool, but it needs Review because dataset names can bypass the intended storage boundary and destructive operations have weak safeguards.

Review before installing. Use only explicit, simple dataset names, avoid storing secrets or regulated personal data, and be careful with delete/drop commands because they can permanently change stored data. The maintainer should validate dataset names consistently in write.py, add confirmation or recovery for destructive operations, and pin installation dependencies.

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/write.py:9
Finding

Dataset Name Validation Bypass Enables Writes Outside the Intended Data Directory

Content
View full analysis

Vulnerability Details

File Location: scripts/write.py:9-67
Vulnerability Type: Improper path validation and path traversal
Risk Level: High

Vulnerable Code

python
def create_dataset(dataset_name, fields):
    try:
        df = pd.DataFrame({
            "_id": [uuid.uuid4().__str__()],
            "dataset_name": [dataset_name],
            "fields": [json.dumps(fields)],
            "_created_at": [datetime.now()]
        })

        metadata_path = os.path.join(get_data_path(), "metadata.lance")
        lance.write_dataset(df, metadata_path, mode="append")

        return create_response("create_dataset", "success", None, None)
    except Exception as e:
        return create_response("create_dataset", "error", None, str(e))

def check_dataset_exists(dataset_name):
    try:
        metadata_path = os.path.join(get_data_path(), "metadata.lance")
        metadata_ds = lance.dataset(metadata_path)
        metadata_df = metadata_ds.to_table().to_pandas()
        matching_rows = metadata_df[metadata_df['dataset_name'] == dataset_name]
        if matching_rows.empty:
            raise ValueError(f"Dataset {dataset_name} does not exist in metadata.")
        fields_data = matching_rows.iloc[0]['fields']
        if isinstance(fields_data, str):
            return json.loads(fields_data)
        else:
            return fields_data
    except Exception as e:
        raise ValueError(f"Error checking dataset metadata: {str(e)}")

def validate_field_count(fields, new_data):
    if len(fields) != len(new_data):
        raise ValueError(f"Number of fields mismatch: expected {len(fields)}, got {len(new_data)}")

def append_to_dataset(new_data, dataset_name):
    try:
        fields = check_dataset_exists(dataset_name)
        validate_field_count(fields, new_data)

        # Create a dictionary with _id, _updated_at, and the field data
        data_dict = {
      
...[truncated 3689 chars]
Remediation
View remediation

Remediation Suggestions

  1. Import and invoke the existing validator in every write operation:

    python
    from manage import (
        get_data_path,
        create_response,
        check_dataset_exists,
        validate_dataset_name,
    )
    
  2. Remove the duplicate check_dataset_exists() implementation from write.py. Use the validated implementation from manage.py so all read, write, and management operations enforce the same policy.

  3. Validate names before storing them in metadata:

    python
    def create_dataset(dataset_name, fields):
        try:
            validate_dataset_name(dataset_name)
            # Continue with metadata creation.
    
  4. Resolve and verify every final dataset path immediately before filesystem access. Prefer os.path.commonpath() over string-prefix checks:

    python
    def safe_dataset_path(dataset_name):
        validate_dataset_name(dataset_name)
        root = os.path.realpath(get_data_path())
        destination = os.path.realpath(os.path.join(root, dataset_name))
    
        if os.path.commonpath([root, destination]) != root:
            raise ValueError("Dataset path escapes the data directory")
    
        return destination
    
  5. Use safe_dataset_path() consistently in append, batch append, update, delete, backup, read, and drop operations.

  6. Reject duplicate dataset names and consider restricting names to a conservative allowlist such as letters, digits, underscores, and hyphens.

  7. Add regression tests covering absolute paths, ../ traversal, both path separator styles, symbolic-link path components, empty names, and valid names.

T08 · Insecure Dependencies

Warning
Location
SKILL.md:14
Finding

Unpinned Installation Dependencies Create a Supply-Chain Integrity Risk

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:14-35; requirements.txt:1-5
Vulnerability Type: Unpinned third-party dependencies and unconstrained installer upgrade
Risk Level: Medium

Vulnerable Code

SKILL.md:14-35:

yaml
        install:
            # Bootstrap pip if missing
            - kind: "shell"
              cmd: "python3 -m ensurepip --upgrade || true"
              label: "Ensure pip is installed"

            # Bootstrap uv if missing
            - kind: "shell"
              cmd: "pip install --upgrade uv || true"
              label: "Install uv if missing"

            # Install pylance
            - kind: "uv"
              type: "pip"
              package: "pylance"
              label: "Install pylance (Lance columnar format) via uv"

            # Install pandas
            - kind: "uv"
              type: "pip"
              package: "pandas"
              label: "Install pandas via uv"

requirements.txt:1-5:

text
# Lance columnar format — PyPI package is 'pylance' but installs as the 'lance' module.
# This is the official Lance project naming convention (see https://github.com/lance-format/lance).
# Do NOT replace 'pylance' with 'lance' here — 'lance' is not a valid PyPI package name.
pylance
pandas

Technical Analysis

The skill installs uv, pylance, and pandas without exact version constraints or artifact hashes. The uv installer is explicitly upgraded to the latest release available at installation time.

This makes installation non-reproducible: two installations of the same audited skill can receive materially different dependency code. If an upstream package release or package-index account is compromised, the installation process may retrieve and execute code that was never reviewed as part of this skill audit.

The commands also use || true, suppressing failures from the bootstrap and installer-upgrad ...[truncated 1794 chars]

Remediation
View remediation

Remediation Suggestions

  1. Pin every dependency to an explicitly reviewed version:

    text
    pylance==<reviewed-version>
    pandas==<reviewed-version>
    
  2. Generate and commit a lockfile containing exact transitive dependency versions.

  3. Require cryptographic hashes for downloaded artifacts where the installation system supports them. Maintain hashes for each supported platform and Python version.

  4. Pin uv rather than upgrading it unconditionally:

    bash
    python3 -m pip install "uv==<reviewed-version>"
    
  5. Remove || true from required installation steps. Installation should fail closed if the expected package manager cannot be installed or verified.

  6. Use only explicitly configured HTTPS package indexes and avoid untrusted additional indexes that could enable dependency confusion.

  7. Establish a dependency-update process that includes vulnerability scanning, provenance review, automated tests, and deliberate lockfile regeneration.

  8. Where supported, use signed artifacts, trusted publishing metadata, attestations, or repository provenance verification before accepting dependency updates.

Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • 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
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (13)

Missing User Warnings

High
Category
Not specified by scanner
Confidence
94% confidence
Finding

The delete path removes a record and then overwrites the dataset on disk, making it a destructive and potentially irreversible operation. The file contains no user-facing warning, confirmation prompt, or disclosure explaining that deletion modifies persistent data.

Content

No source excerpt is available for this finding.

Ae2

Medium
Category
analysis-evasion
Confidence
90% confidence
Finding

Artifact content does not match its filename extension

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill performs persistent file writes but does not declare any tool scope or permission boundary. That increases the chance the host agent invokes storage behavior without explicit user or platform controls, making unintended persistence and local data modification more likely.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The trigger phrases are broad and common, such as 'remember this' and 'store for later', which can cause the skill to activate in situations where the user did not intend durable storage. In a persistence-oriented skill, accidental invocation is dangerous because it can silently retain sensitive or contextual data across sessions.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill description encourages persistent storage but does not clearly warn that stored data may include sensitive information and remain available across sessions. Users or upstream agents may therefore persist secrets, personal data, or confidential context without informed consent or retention awareness.

Content

No source excerpt is available for this finding.

Ssd 3

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The skill explicitly promotes storing conversation context, skill outputs, research data, and 'remember this' information across sessions, but provides no limiting guidance on sensitive data handling. In this context, the absence of guardrails materially raises the risk of privacy leakage, cross-session data exposure, and retention of secrets or confidential user content.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

The delete-dataset-record command is defined as a deletion operation and is executed directly via delete_dataset_record(args.dataset_name, args.record_id) with no confirmation, warning output, or explanatory comment in this file. Because this is a safety-relevant destructive operation in code, some user-facing disclosure is expected.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

This code exposes drop-dataset and routes directly to drop_dataset(args.dataset_name) without any visible confirmation prompt, warning print, or inline documentation about the destructive action. For a code file, destructive or irreversible operations should have some form of user disclosure unless such warning is clearly provided elsewhere, which is not shown here.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The drop_dataset function performs irreversible deletion of both the dataset directory and its metadata entry immediately after validating the name and existence, with no confirmation, soft-delete, or safety interlock. In a skill designed for persistent storage across sessions, accidental invocation, prompt ambiguity, or agent misuse could cause permanent data loss for user-stored information.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The code performs a full dataset overwrite during record updates, which is a destructive file write operation. Although internal comments describe the step, there is no user-facing confirmation, warning, logging, or disclosure in this file before replacing the stored dataset.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
92% confidence
Finding

The dependency pylance is unpinned, so installs can resolve to different versions over time, reducing build reproducibility and increasing supply-chain risk if a future release is compromised or introduces breaking behavior. In a persistence/storage skill, dependency integrity matters because the package will handle user data and may be loaded in repeated automated environments.

Content

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

text
# Lance columnar format — PyPI package is 'pylance' but installs as the 'lance' module.
# This is the official Lance project naming convention (see https://github.com/lance-format/lance).
# Do NOT replace 'pylance' with 'lance' here — 'lance' is not a valid PyPI package name.
pylance
pandas

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
96% confidence
Finding

The dependency pandas is unpinned, which creates non-reproducible installs and exposes the skill to unexpected vulnerable or incompatible releases. Because this skill stores and analyzes structured data across sessions, a compromised or unsafe dependency could affect confidentiality or integrity of persisted user data.

Content

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

text
# This is the official Lance project naming convention (see https://github.com/lance-format/lance).
# Do NOT replace 'pylance' with 'lance' here — 'lance' is not a valid PyPI package name.
pylance
pandas

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

pandas has a referenced advisory, and because no version is pinned it is impossible to determine from this manifest whether an affected release will be installed. While the cited CVE is disputed and may require unsafe deserialization usage elsewhere in code, the unbounded dependency still leaves exposure uncertain and therefore represents a real supply-chain hygiene weakness.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.