Back to skill

Security audit

Lab Inventory Predictor

Security checks for vulnerabilities and agentic risk

Overview

The skill has a legitimate lab-inventory purpose, but its script can read or overwrite user-selected JSON files despite documentation claiming workspace-only path restrictions.

Review before installing. The main issue is not hidden malware, but the script should enforce an approved workspace path before opening or saving inventory data. Until fixed, only run it with trusted, explicit inventory paths and avoid mutating actions on paths supplied by untrusted input. Removing the unnecessary dependency and adding confirmation for deletion would also reduce risk.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/main.py:76
Finding

Unrestricted Inventory Path Permits Arbitrary File Read and Overwrite

Content
View full analysis

Vulnerability Details

File Location: scripts/main.py:76-98, with the user-controlled argument introduced at scripts/main.py:381 and passed to the vulnerable code at scripts/main.py:406
Vulnerability Type: Path traversal and missing filesystem access-control validation
Risk Level: High

Vulnerable Code

python
def __init__(self, data_path: Optional[str] = None):
    self.data_path = data_path or self.DEFAULT_DATA_PATH
    self.data = self._load_data()

def _load_data(self) -> Dict:
    """Load data file"""
    if os.path.exists(self.data_path):
        with open(self.data_path, 'r', encoding='utf-8') as f:
            return json.load(f)
    return {
        "settings": {
            "default_safety_days": 7,
            "default_lead_time_days": 3,
            "prediction_lookback_days": 30
        },
        "reagents": []
    }

def _save_data(self):
    """Save data file"""
    os.makedirs(os.path.dirname(self.data_path), exist_ok=True)
    with open(self.data_path, 'w', encoding='utf-8') as f:
        json.dump(self.data, f, ensure_ascii=False, indent=2)

The unvalidated path originates from the command line:

python
parser.add_argument('--data-path', help='Data file path')

It is then passed directly to the inventory implementation:

python
predictor = InventoryPredictor(args.data_path)

Technical Analysis

The --data-path value is under user control and is used directly by os.path.exists, open, and os.makedirs. The implementation does not canonicalize the path, enforce a permitted base directory, reject traversal components, or protect against symbolic-link redirection.

Consequently, paths such as /outside/workspace/file.json or paths containing ../ can escape the intended inventory workspace. A symbolic link inside an allowed-looking directory could likewise resolve to a file elsewhere.

This behavior directly contra ...[truncated 2125 chars]

Remediation
View remediation

Remediation Suggestions

  1. Define a single trusted workspace root and resolve it before processing user input.
  2. Resolve the requested path with Path.resolve() before any existence check, read, directory creation, or write.
  3. Verify that the resolved path is a descendant of the trusted workspace using Path.is_relative_to() on supported Python versions or a safe relative_to() check.
  4. Reject absolute paths outside the workspace and traversal paths that resolve outside it.
  5. Reject symbolic links for both the target and relevant parent components, or open files using platform facilities that prevent symbolic-link following.
  6. Restrict accepted targets to regular files with the expected .json extension.
  7. Write updates atomically to a temporary file inside the same approved directory, validate the serialized data, and then replace the intended inventory file.
  8. Apply restrictive file permissions so inventory data is not exposed to unrelated local users.
  9. Return a clear validation error before constructing InventoryPredictor when the path is outside the authorized root.
  10. Add tests covering absolute-path escape, ../ traversal, symbolic-link escape, nonexistent parent directories, and valid in-workspace paths.

T08 · Insecure Dependencies

Note
Location
requirements.txt:1
Finding

Unnecessary and Unpinned Third-Party Dataclasses Dependency

Content
View full analysis

Vulnerability Details

File Location: requirements.txt:1; related installation instructions at SKILL.md:38-44
Vulnerability Type: Unnecessary unpinned supply-chain dependency
Risk Level: Low

Vulnerable Code

requirements.txt contains:

text
dataclasses

The related prerequisite documentation states:

markdown
- **Python 3.8+ is strictly required** (uses `dataclasses` module). On Python 3.6 the script will fail at import with `ModuleNotFoundError`. Upgrade with `pyenv install 3.8` or `conda create -n lab python=3.8`.
- The script should include a version guard: `if sys.version_info < (3, 8): sys.exit('Error: Python 3.8+ required')` before the dataclasses import.
- No external dependencies (uses only standard library)

```text
pip install -r requirements.txt
text

### Technical Analysis

The project declares Python 3.8 or later as mandatory. `dataclasses` is part of the Python standard library in every supported runtime, so installing a separately distributed `dataclasses` package is unnecessary.

The dependency has no version constraint or integrity hash. Following the documented installation command therefore causes package content to be resolved dynamically from the configured package index. This creates avoidable exposure to package-index compromise, dependency substitution, compromised releases, or unsafe index configuration.

It also contradicts the documentation's statement that the project has no external dependencies.

### Attack Path

1. A user follows the documented setup procedure:
   ```bash
   pip install -r requirements.txt
   ```
2. `pip` queries the configured package index for the unpinned `dataclasses` distribution.
3. If the configured index, resolved release, network path, or package publisher is compromised, attacker-controlled package content may be installed.
4. Malicious installation or runtime package behavior executes with the privileges of
...[truncated 785 chars]
Remediation
View remediation

Remediation Suggestions

  1. Remove dataclasses from requirements.txt.
  2. Remove the pip install -r requirements.txt instruction when the file has no required dependencies, or clearly state that no package installation is necessary.
  3. Retain Python 3.8 or later as the enforced minimum runtime.
  4. If dependencies are introduced later, pin exact versions and use cryptographic hashes through a locked requirements file.
  5. Install packages only from explicitly trusted indexes.
  6. Add dependency review and vulnerability scanning to the release process.
  7. Keep dependency documentation synchronized with the actual runtime requirements.
Vulnerability Patterns
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Output HandlingUnvalidated Output Injection, Cross-Context Output, Unbounded Output
  • 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 (7)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill documents file read/write behavior via a default inventory data file and report output path, but it does not declare any explicit tool scope such as permissions or allowed-tools. This creates an authorization gap: an agent or runtime may permit broader filesystem access than intended, making accidental or unauthorized reads/writes harder to constrain and audit.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

This report contains a material security contradiction: it claims path traversal protection is documented/enforced, while the recommendations later acknowledge the script does not actually implement the check. That can mislead reviewers into approving a skill that may open attacker-controlled file paths via --data-file, enabling unauthorized file reads within the agent/workspace context.

Content

No source excerpt is available for this finding.

Unbounded Output

Medium
Category
Output Handling
Confidence
60% confidence
Finding

Output size or generation rate is not bounded. Unbounded output enables denial-of-service through resource exhaustion, log flooding, or context-window stuffing.

Content

Scanner excerpt · lab-inventory-predictor_audit_result_v4.json (reported line 248)May include surrounding context.

json
"assertions_total": 4,
        "assertions": [
          {
            "text": "Output covers all 20 reagents without truncation",
            "result": "PASS",
            "note": "Confirmed: output covers all 20 reagents without truncation as expected."
          },

Unbounded Output

Medium
Category
Output Handling
Confidence
60% confidence
Finding

Output size or generation rate is not bounded. Unbounded output enables denial-of-service through resource exhaustion, log flooding, or context-window stuffing.

Content

Scanner excerpt · lab-inventory-predictor_audit_result_v4.json (reported line 250)May include surrounding context.

json
"assertions_total": 4,
        "assertions": [
          {
            "text": "Output covers all 20 reagents without truncation",
            "result": "PASS",
            "note": "Confirmed: output covers all 20 reagents without truncation as expected."
          },

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
99% confidence
Finding

These lines explicitly admit that path traversal validation was only documented and not enforced in the script, confirming a genuine missing security control. If an agent or user can supply --data-file, an attacker may read unintended files or influence processing by pointing the skill at data outside the intended workspace.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The remove_reagent operation permanently deletes an entry from the inventory data and immediately saves the modified file, but there is no confirmation prompt or explicit warning in the command interface about this destructive action. Although the function has a brief docstring, it does not meaningfully disclose the irreversible effect to the user at the point of use.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
60% confidence
Finding

Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Content

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

text
dataclasses

Static analysis

No suspicious patterns detected.