Back to skill

Security audit

Batch Rename

Security checks for vulnerabilities and agentic risk

Overview

This is a normal batch-renaming tool, but its restore and overwrite handling can move or destroy files beyond what users may reasonably expect.

Review before installing. Use preview mode first, avoid --force unless you have an independent backup, and do not run the restore command in directories supplied by someone else or containing an untrusted .rename_backup.json. Treat rename operations as potentially irreversible until the tool creates and validates its own backup manifest.

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 (3)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/rename.py:109
Finding

Existing destination files can be overwritten without the force option

Content
View full analysis

Vulnerability Details

File Location: scripts/rename.py, lines 109-130
Vulnerability Type: Unsafe file replacement and incomplete conflict validation
Risk Level: Medium

Vulnerable Code:

python
# First, check for conflicts
new_names = [r['new_img'] for r in renames]
if len(new_names) != len(set(new_names)):
    print("Error: Duplicate filenames would be created")
    return

# Rename files
renamed_images = 0
renamed_annotations = 0
errors = []

for r in renames:
    old_path = Path(args.directory) / Path(r['old_img']).name
    new_path = Path(args.directory) / r['new_img']

    try:
        # Handle overwrite
        if args.force and new_path.exists():
            new_path.unlink()

        old_path.rename(new_path)
        renamed_images += 1

        # Rename annotation if exists
        if r['old_ann'] and r['new_ann']:
            if args.force and r['new_ann'].exists():
                r['new_ann'].unlink()
            r['old_ann'].rename(r['new_ann'])
            renamed_annotations += 1

Technical Analysis

The preflight check only determines whether multiple source images generate the same destination name. It does not determine whether a generated image or annotation destination already exists on disk.

The existence checks are only used to explicitly delete destinations when --force is enabled. Without that option, the code still invokes Path.rename() against the destination. On platforms where the underlying rename operation replaces existing files, this can silently overwrite destination content despite the absence of explicit overwrite authorization.

Conflict validation is also performed only for generated image names. Existing annotation destinations and duplicate generated annotation paths are not comprehensively validated. Because image and annotation changes are applied incrementally, a conflict or error encountered partway through processin ...[truncated 1112 chars]

Remediation
View remediation

Remediation Suggestions

  • Resolve and validate every source and destination before making any filesystem changes.
  • Reject any existing destination unless --force was explicitly supplied.
  • Apply the same conflict checks to image and annotation destinations.
  • Detect duplicate generated annotation names in addition to duplicate image names.
  • Ensure that a destination which is also a source in the same batch is handled safely.
  • Use a two-phase rename process: first move all sources to unique temporary names within the same filesystem, then move them to their final destinations.
  • Record a complete transaction manifest before mutation and roll back all completed operations if any step fails.
  • When force mode is enabled, back up existing destination files rather than unlinking them immediately.
  • Use resolved-path containment checks to ensure all final destinations remain inside their intended directories.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/rename.py:143
Finding

Restore operation trusts attacker-controlled paths from the backup file

Content
View full analysis

Vulnerability Details

File Location: scripts/rename.py, lines 143-169
Vulnerability Type: Arbitrary file relocation through unvalidated backup entries
Risk Level: High

Vulnerable Code:

python
def cmd_restore(args):
    """Restore from backup"""
    backup_file = Path(args.directory) / ".rename_backup.json"

    if not backup_file.exists():
        print("No backup found")
        return

    import json
    with open(backup_file, 'r') as f:
        backup = json.load(f)

    print(f"Found backup with {len(backup)} files")

    confirm = input("Restore original filenames? (y/n): ")
    if confirm.lower() != 'y':
        print("Cancelled")
        return

    restored = 0
    for item in backup:
        try:
            current = Path(item['current'])
            original = Path(item['original'])
            if current.exists():
                current.rename(original)
                restored += 1
        except Exception as e:
            print(f"Error: {e}")

    print(f"✓ Restored {restored} files")
    backup_file.unlink()

Technical Analysis

The restore command treats the contents of .rename_backup.json as trusted filesystem paths. The current and original fields are passed directly to Path and then used in a rename operation without schema validation, path normalization, extension validation, or containment enforcement.

Consequently, backup entries can contain absolute paths or relative paths with traversal components. Neither endpoint is required to reside in the directory supplied on the command line. If an attacker can place or modify .rename_backup.json in a directory that a victim later restores, the file can instruct the program to move any file accessible to the victim to another writable location.

The generic confirmation prompt only reports the number of entries. It does not display the source and destination paths, so it does not ...[truncated 1629 chars]

Remediation
View remediation

Remediation Suggestions

  • Accept only relative filenames in backup records; reject absolute paths and any path containing traversal components.
  • Resolve the image and annotation roots and verify with Path.resolve() that every source and destination remains beneath an explicitly approved root.
  • Define and validate a strict JSON schema, including required fields, string types, permitted extensions, unique entries, and a bounded entry count.
  • Generate backup manifests exclusively through the rename operation and write them atomically with restrictive permissions.
  • Add an integrity mechanism, such as an authenticated checksum tied to locally generated state, if backup files may be exposed to untrusted writers.
  • Display every resolved source-to-destination mapping before confirmation.
  • Reject existing destinations by default and require separate explicit authorization for replacement.
  • Preserve the backup when any restoration operation fails.
  • Implement transactional restoration and rollback so that a partial restore does not leave the filesystem inconsistent.

other

Note
Location
SKILL.md:11
Finding

Advertised undo support is not implemented by the rename operation

Content
View full analysis

Vulnerability Details

File Location: SKILL.md, line 11; scripts/rename.py, lines 142-169
Vulnerability Type: Misleading recovery capability and missing transactional backup
Risk Level: Low

Relevant Documentation:

markdown
- **Undo Support**: Restore original filenames

Relevant Code:

python
def cmd_restore(args):
    """Restore from backup"""
    backup_file = Path(args.directory) / ".rename_backup.json"

    if not backup_file.exists():
        print("No backup found")
        return

    import json
    with open(backup_file, 'r') as f:
        backup = json.load(f)

Technical Analysis

The documentation states that the Skill supports undoing rename operations. The restore implementation requires a .rename_backup.json file, but the audited rename implementation never creates that file or records image and annotation mappings.

Users may therefore authorize a destructive batch operation under the mistaken assumption that the built-in restore command can reverse it. This is particularly significant because rename operations are performed incrementally and errors are collected rather than triggering a transaction rollback. A failed or interrupted operation can leave files partially renamed with no automatically generated recovery manifest.

Attack Path

  1. A user relies on the documented undo capability and performs a batch rename.
  2. Existing files are replaced, an annotation rename fails, or execution is interrupted after only some files have been changed.
  3. The user invokes the restore command to recover the original names.
  4. The command reports No backup found because the rename command did not create .rename_backup.json.
  5. The user must reconstruct the original mappings manually, and overwritten content may be unrecoverable.

This issue does not require a malicious actor, although an attacker could exploit the user's confidence in the docume ...[truncated 408 chars]

Remediation
View remediation

Remediation Suggestions

  • Create a complete backup manifest atomically before the first filesystem mutation.
  • Record original and final mappings for both images and annotations.
  • Use paths relative to validated dataset roots rather than unrestricted absolute paths.
  • Flush and safely persist the manifest before applying any rename.
  • Keep the manifest until restoration succeeds completely or the user explicitly discards it.
  • Integrate rollback into the rename operation so failures automatically reverse prior changes.
  • Add automated tests for successful restoration, interrupted operations, collisions, malformed manifests, and annotation failures.
  • If undo support will not be implemented, remove the claim from SKILL.md and clearly warn that rename operations may be irreversible.
Vulnerability Patterns
  • Rogue AgentSelf-Modification, Session Persistence
  • 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
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (5)

Self-Modification

High
Category
Rogue Agent
Confidence
85% confidence
Finding

Skill modifies its own code, configuration, or behavior at runtime. Self-modification enables an agent to escalate privileges, disable safety constraints, or install persistent backdoors.

Content

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

md
- `--start`: Starting number for sequential renaming
- `--annotations`: Path to annotation files (will be renamed together)
- `--preview`: Preview changes without applying
- `--force`: Overwrite existing files

Self-Modification

High
Category
Rogue Agent
Confidence
85% confidence
Finding

Skill modifies its own code, configuration, or behavior at runtime. Self-modification enables an agent to escalate privileges, disable safety constraints, or install persistent backdoors.

Content

Scanner excerpt · scripts/rename.py (reported line 209)May include surrounding context.

python
- `--start`: Starting number for sequential renaming
- `--annotations`: Path to annotation files (will be renamed together)
- `--preview`: Preview changes without applying
- `--force`: Overwrite existing files

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill documents a --force option that overwrites existing files but does not clearly warn about irreversible data loss or advise safeguards. In a batch-renaming context, this is dangerous because users may unintentionally destroy images or annotations at scale, especially when filenames collide.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The script exposes a restore workflow that depends on .rename_backup.json, but the rename path never creates that backup before modifying files. This can mislead users into believing renames are reversible when they are not, increasing the chance of permanent data loss after bulk file operations or forced overwrites.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

This is the same underlying issue as SDI-4: the script claims it can restore from backup, but no backup is ever generated during rename operations. In a batch-renaming tool, that mismatch is dangerous because users may proceed with destructive changes under a false assumption of recoverability.

Content

No source excerpt is available for this finding.