Back to skill

Security audit

File Manager Secure

Security checks for vulnerabilities and agentic risk

Overview

This skill is a file manager with no evidence of theft or remote code, but its promised safety controls can be bypassed in ways that may move or restore files outside the intended workspace.

Review before installing. The skill is not malicious on its face, but do not use it for important directories until delete-confirm revalidates paths, restore refuses metadata destinations outside the workspace, bulk limits are enforced, and execution is bound to a trusted dry-run plan.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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 (3)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/file_manager.py:394
Finding

Caller-Supplied Delete Plan Bypasses Workspace Path Validation

Content
View full analysis

Vulnerability Details

File Location: scripts/file_manager.py, lines 281-286 and 394-402
Vulnerability Type: Execution-time path validation bypass
Risk Level: High

Vulnerable Code:

python
def execute_delete(operations: List[FileOperation]) -> Tuple[bool, List[str]]:
    """Execute delete operations (move to trash)."""
    results = []
    for op in operations:
        success, msg = move_to_trash(Path(op.source))
        results.append(f"{'✓' if success else '✗'} {op.source}: {msg}")
    return True, results
python
elif cmd == "delete-confirm":
    if len(sys.argv) < 3:
        print(json.dumps({"error": "Operations JSON required"}, indent=2))
        sys.exit(1)
    try:
        ops_data = json.loads(sys.argv[2])
        operations = [FileOperation(**op) for op in ops_data]
        success, results = execute_delete(operations)

Technical Analysis

The initial deletion-planning function calls validate_path(), but the execution endpoint does not require operations to originate from that planner. Instead, delete-confirm deserializes arbitrary caller-supplied JSON directly into FileOperation objects.

execute_delete() then passes each untrusted source value directly to move_to_trash() without repeating workspace containment checks, forbidden-pattern checks, existence checks, or operation-type validation. Consequently, the security boundary implemented by validate_path() can be bypassed by calling the execution command directly.

The confirm_required field is also caller-controlled and is not enforced. No integrity mechanism binds an execution request to a previously generated plan.

Attack Path

  1. Identify a filesystem file or directory accessible to the process but located outside OPENCLAW_WORKSPACE.
  2. Construct a JSON operation array containing that absolute path, for example:
    json
    [{
      "op": "delete",
      "source": 
    

...[truncated 949 chars]

Remediation
View remediation

Remediation Suggestions

  • Call validate_path() on every operation source immediately before execution.
  • Require the resolved source to remain beneath an explicitly configured allowed root.
  • Reject unsupported operation names and ignore caller-supplied confirm_required and size values.
  • Bind execution requests to server-generated plans using a random plan identifier or an authenticated signature.
  • Store plans internally rather than accepting complete operation objects from the command line.
  • Recalculate target metadata and total size during execution.
  • Defend against time-of-check/time-of-use and symlink races by using descriptor-relative filesystem APIs where available.
  • Return an overall failure status if any individual operation fails.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/file_manager.py:143
Finding

Untrusted Trash Metadata Controls the Restore Destination

Content
View full analysis

Vulnerability Details

File Location: scripts/file_manager.py, lines 143-160
Vulnerability Type: Unvalidated destination path from mutable metadata
Risk Level: High

Vulnerable Code:

python
# Read metadata
if meta_file.exists():
    with open(meta_file) as f:
        metadata = json.load(f)
    original_path = Path(metadata["original_path"])
else:
    # Fallback: restore to workspace root
    original_path = WORKSPACE / filename

# Ensure parent exists
original_path.parent.mkdir(parents=True, exist_ok=True)

# Restore
shutil.move(str(trash_path), str(original_path))
if meta_file.exists():
    meta_file.unlink()

Technical Analysis

Trash metadata is stored as an ordinary JSON file inside the workspace trash directory. During restoration, the original_path field is treated as authoritative even though the file can be modified independently of the trashed object.

The destination is not passed through validate_path(), canonicalized against an allowed root, checked for symlinks, or checked for an existing destination. The function also creates destination parent directories before moving the file.

This creates a path injection vulnerability: a modified .trashmeta file can direct a restore operation to an arbitrary path available to the process.

Attack Path

  1. Create or identify a valid file in WORKSPACE/.trash whose name matches the restore lookup pattern.
  2. Create or modify its corresponding .trashmeta JSON file.
  3. Set original_path to an absolute path outside the workspace, such as a process-accessible application configuration path.
  4. Invoke the restore command using the matching filename.
  5. The implementation reads the attacker-controlled destination from the metadata.
  6. It creates missing parent directories and moves the trashed object to that destination.
  7. Depending on platform and destination semantics, an existing target may be overwri ...[truncated 557 chars]
Remediation
View remediation

Remediation Suggestions

  • Resolve and validate original_path with the same allowed-root policy used for normal operations.
  • Reject absolute or canonical destinations outside the workspace.
  • Do not overwrite existing destinations by default; require a separate explicit and authenticated overwrite decision.
  • Protect trash metadata with restrictive permissions and an authenticated integrity value.
  • Store restore records in an internal database or protected index rather than trusting adjacent mutable JSON.
  • Validate the metadata schema, expected trash path, original path, filename, and entry identifier.
  • Prevent symlink traversal at every destination path component.
  • Restore through descriptor-relative, no-follow filesystem operations where the platform supports them.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/file_manager.py:27
Finding

Documented Bulk Operation Limits Are Defined but Never Enforced

Content
View full analysis

Vulnerability Details

File Location: scripts/file_manager.py, lines 27-28 and 281-286
Vulnerability Type: Missing resource and destructive-operation limits
Risk Level: Medium

Vulnerable Code:

python
MAX_BULK_OPERATIONS = 50
MAX_TOTAL_SIZE_MB = 100
python
def execute_delete(operations: List[FileOperation]) -> Tuple[bool, List[str]]:
    """Execute delete operations (move to trash)."""
    results = []
    for op in operations:
        success, msg = move_to_trash(Path(op.source))
        results.append(f"{'✓' if success else '✗'} {op.source}: {msg}")
    return True, results

Technical Analysis

The implementation defines maximum operation-count and total-size settings, and SKILL.md describes these values as bulk-protection controls. Neither value is checked during deletion planning or execution.

Because delete-confirm accepts a complete caller-supplied array, a caller can submit an arbitrarily large number of operations. The supplied size fields are not recalculated, and no explicit force authorization is required.

The absence of execution-time enforcement makes the documented safety controls ineffective and amplifies the impact of the path-validation bypass.

Attack Path

  1. Generate a JSON array containing more than 50 deletion operations or operations whose actual combined size exceeds 100 MB.
  2. Pass the array directly to delete-confirm.
  3. The implementation deserializes every entry without checking operation count or aggregate size.
  4. execute_delete() iterates over the entire array and attempts every move-to-trash operation.
  5. The documented limit and force requirement never take effect.

Impact Assessment

A caller can trigger large-scale file movement, exhaust workspace trash storage, consume substantial disk I/O, and cause service disruption. When combined with the execution-time path-validation bypass, the operation set can include ...[truncated 216 chars]

Remediation
View remediation

Remediation Suggestions

  • Enforce MAX_BULK_OPERATIONS during both planning and execution.
  • Recalculate each source's actual size immediately before execution and enforce the aggregate byte limit.
  • Reject oversized plans by default.
  • Implement a distinct, explicit force mechanism with clear authorization and audit logging.
  • Prevent callers from bypassing limits by splitting or modifying an approved plan through integrity-protected plan identifiers.
  • Reserve sufficient trash capacity before starting a batch and stop safely if resource limits are reached.
  • Report partial failures accurately rather than always returning a successful overall status.
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • 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 (10)

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

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

md
FORBIDDEN_PATTERNS = [
    r"\.\.", r"\.ssh", r"\.gnupg", r"\.aws", r"\.docker", r"\.kube",
    r"\.env", r"secret", r"token", r"credential", r"password",
    r"/etc/shadow", r"/etc/passwd", r"System32", r"REGISTRY"
]

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/file_manager.py (reported line 32)May include surrounding context.

python
FORBIDDEN_PATTERNS = [
    r"\.\.", r"\.ssh", r"\.gnupg", r"\.aws", r"\.docker", r"\.kube",
    r"\.env", r"secret", r"token", r"credential", r"password",
    r"/etc/shadow", r"/etc/passwd", r"System32", r"REGISTRY"
]

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

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

md
FORBIDDEN_PATTERNS = [
    r"\.\.", r"\.ssh", r"\.gnupg", r"\.aws", r"\.docker", r"\.kube",
    r"\.env", r"secret", r"token", r"credential", r"password",
    r"/etc/shadow", r"/etc/passwd", r"System32", r"REGISTRY"
]

# ============== DATA CLASSES ==============

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/file_manager.py (reported line 33)May include surrounding context.

python
FORBIDDEN_PATTERNS = [
    r"\.\.", r"\.ssh", r"\.gnupg", r"\.aws", r"\.docker", r"\.kube",
    r"\.env", r"secret", r"token", r"credential", r"password",
    r"/etc/shadow", r"/etc/passwd", r"System32", r"REGISTRY"
]

# ============== DATA CLASSES ==============

Credential Access

High
Category
Privilege Escalation
Confidence
95% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

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

md
FORBIDDEN_PATTERNS = [
    r"\.\.", r"\.ssh", r"\.gnupg", r"\.aws", r"\.docker", r"\.kube",
    r"\.env", r"secret", r"token", r"credential", r"password",
    r"/etc/shadow", r"/etc/passwd", r"System32", r"REGISTRY"
]

# ============== DATA CLASSES ==============

Credential Access

High
Category
Privilege Escalation
Confidence
95% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/file_manager.py (reported line 33)May include surrounding context.

python
FORBIDDEN_PATTERNS = [
    r"\.\.", r"\.ssh", r"\.gnupg", r"\.aws", r"\.docker", r"\.kube",
    r"\.env", r"secret", r"token", r"credential", r"password",
    r"/etc/shadow", r"/etc/passwd", r"System32", r"REGISTRY"
]

# ============== DATA CLASSES ==============

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The script advertises secure, dry-run-oriented file operations, but the delete-confirm path accepts user-supplied JSON operations and executes them without revalidating source paths against the workspace restrictions. An attacker can bypass plan_delete entirely and submit arbitrary file paths to move_to_trash, enabling unauthorized deletion/move of files outside the intended workspace if the process has filesystem permissions.

Content

No source excerpt is available for this finding.

Tainted flow: 'LOG_FILE' from os.environ.get (line 24, credential/environment) → open (file write)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/file_manager.py (reported line 92)May include surrounding context.

python
LOG_FILE.parent.mkdir(parents=True, exist_ok=True)
    timestamp = datetime.now().isoformat()
    log_entry = f"[{timestamp}] {operation} | src={source} | dest={dest} | status={status}\n"
    with open(LOG_FILE, "a", encoding="utf-8") as f:
        f.write(log_entry)

# ============== TRASH MANAGEMENT ==============

Tainted flow: 'meta_file' from os.environ.get (line 143, credential/environment) → open (file write)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/file_manager.py (reported line 124)May include surrounding context.

python
"size": trash_path.stat().st_size if trash_path.is_file() else 0,
        }
        meta_file = trash_path.with_suffix(trash_path.suffix + ".trashmeta")
        with open(meta_file, "w") as f:
            json.dump(metadata, f, indent=2)
        
        log_operation("DELETE_TO_TRASH", str(path), str(trash_path))

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

restore_from_trash restores files to disk immediately based on a caller-supplied filename, with no confirmation gate or revalidation that the original_path from trash metadata is still inside the allowed workspace. If metadata is tampered with, or if trash contents are attacker-controlled, this can write files to unintended locations and overwrite existing data, making the execution path more dangerous than the 'safe recovery' framing suggests.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.