Back to skill

Security audit

Microscopy Scale Bar Adder

Security checks for vulnerabilities and agentic risk

Overview

The skill has a coherent image-annotation purpose, but its script can read from or write to absolute paths outside the workspace despite claiming that such paths are blocked.

Review this skill before installing. It appears intended for legitimate microscopy image annotation, but use it only with trusted image paths and explicit output locations. Do not rely on its claimed workspace isolation until the path validation is fixed to reject absolute paths, resolve symlinks, and avoid overwriting files unless explicitly requested.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/main.py:17
Finding

Workspace Boundary Bypass Through Incomplete Path Validation

Content
View full analysis

Vulnerability Details

File Location: scripts/main.py:17-21, with file access sinks at scripts/main.py:122 and scripts/main.py:158-167
Vulnerability Type: Improper path validation and insufficient workspace containment
Risk Level: Medium

Vulnerable Code

python
def check_path_traversal(path: str) -> None:
    """Reject paths containing directory traversal sequences."""
    if "../" in path or path.startswith(".."):
        print(f"Error: path traversal detected in '{path}'. Absolute or traversal paths are not allowed.", file=sys.stderr)
        sys.exit(1)

The validation is applied before the input and output paths are used:

python
# Security: reject path traversal
check_path_traversal(args.input)
check_path_traversal(args.output)

if not os.path.isfile(args.input):
    print(f"Error: input file not found: {args.input}", file=sys.stderr)
    sys.exit(1)

The accepted paths subsequently reach Pillow file operations without canonicalization or workspace-containment checks:

python
image = Image.open(input_path).convert("RGBA")
python
try:
    img_probe = Image.open(args.input)
    pixels_per_unit = read_tiff_pixels_per_unit(img_probe)
    img_probe.close()
except Exception:
    pixels_per_unit = None
python
image.save(output_path)

Technical Analysis

The check_path_traversal function only searches for textual ../ patterns or paths beginning with ... It does not canonicalize paths, reject absolute paths, establish an approved workspace root, or verify that the resolved path remains beneath that root.

As a result, paths such as /tmp/external/image.png contain no prohibited substring and pass validation. A relative path pointing to an in-workspace symbolic link can also pass the textual check even when the link resolves outside the workspace.

This behavior conflicts with the security boundary documented in SKILL.md, which states that absolute paths outside the workspace must be rejected ...[truncated 1998 chars]

Remediation
View remediation

Remediation Suggestions

Replace substring-based validation with canonical path containment checks:

  1. Define the trusted workspace root explicitly and resolve it:

    python
    from pathlib import Path
    
    WORKSPACE = Path.cwd().resolve()
    
  2. Resolve each supplied path and verify that it remains beneath the workspace:

    python
    def resolve_workspace_path(raw_path: str) -> Path:
        candidate = Path(raw_path)
    
        if candidate.is_absolute():
            raise ValueError(f"Absolute path is not allowed: {raw_path}")
    
        resolved = (WORKSPACE / candidate).resolve()
    
        if not resolved.is_relative_to(WORKSPACE):
            raise ValueError(f"Path escapes workspace: {raw_path}")
    
        return resolved
    
  3. On Python versions without Path.is_relative_to, use os.path.commonpath carefully:

    python
    if os.path.commonpath([str(WORKSPACE), str(resolved)]) != str(WORKSPACE):
        raise ValueError(f"Path escapes workspace: {raw_path}")
    
  4. Apply the resolved path returned by the validator to every subsequent operation. Do not validate one string and later use the original unvalidated string.

  5. Decide on and enforce a symbolic-link policy. If symbolic links are unnecessary, reject any path component that is a symbolic link. Otherwise, always perform containment checks on the fully resolved target.

  6. Validate the output parent directory after resolution, require it to exist beneath the workspace, and avoid overwriting existing files unless overwrite behavior is explicitly authorized. Exclusive creation or an explicit --overwrite option should be considered.

  7. Add regression tests covering:

    • Absolute input and output paths.
    • ../ traversal.
    • Nested traversal sequences.
    • Symbolic links resolving outside the workspace.
    • Valid files in nested workspace directories.
    • Attempts to overwrite existing output files.
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
Findings (1)

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
79% confidence
Finding

This markdown file documents a workflow that writes a new image with an added scale bar, which affects user data on disk. Although the behavior is implied by the skill purpose, the description does not include an explicit caution or disclosure about file output/overwriting considerations for users.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.