T09 · Insecure Skill Coding Practices
- Location
scripts/organize-files.ps1:53- Finding
Recursive destination collisions can cause partial filesystem reorganization
- Content
View full analysis
Vulnerability Details
File Location:
scripts/organize-files.ps1, lines 53–75 and 90–96
Vulnerability Type: Non-atomic destination collision handling
Risk Level: MediumVulnerable Code
powershell # --- Collect loose files --- $files = Get-ChildItem -LiteralPath $target -File -Recurse:$Recurse | Where-Object { $_.Name -notlike ".*" -and $_.FullName -ne $scriptFullName -and $_.Name -ne "organize-report.md" } if ($files.Count -eq 0) { Write-Host "No files to organize in $target" exit 0 } # --- Plan the moves --- $plan = foreach ($f in $files) { $cat = Get-Category $f $destDir = Join-Path $target $cat $dest = Join-Path $destDir $f.Name $i = 1 while (Test-Path -LiteralPath $dest) { $name = [System.IO.Path]::GetFileNameWithoutExtension($f.Name) $ext = $f.Extension $dest = Join-Path $destDir "$name ($i)$ext" $i++ } [PSCustomObject]@{ File = $f.Name Category = $cat From = $f.FullName To = $dest } }powershell # --- Execute --- $moved = 0 foreach ($p in $plan) { $destDir = Split-Path -Parent $p.To New-Item -ItemType Directory -Path $destDir -Force | Out-Null Move-Item -LiteralPath $p.From -Destination $p.To $moved++ }Technical Analysis
The script calculates every destination before moving any files. Its collision check uses
Test-Path, which only detects paths that already exist on disk. It does not detect duplicate destination paths generated earlier in the same in-memory plan.When
-Recurseis enabled, two files in different source subdirectories can have the same filename and category. If the corresponding destination does not exist during planning, both entries receive the sameTopath. During execution, the first move succeeds and the second fails because its destination has just been created.Because
$ErrorActionPreferenceis set toStopand the script h ...[truncated 1510 chars]- Remediation
View remediation
Remediation Suggestions
- Maintain a case-insensitive set of reserved destination paths while building the plan. Treat both existing filesystem paths and paths already assigned to earlier plan entries as collisions.
- Generate numeric suffixes until the candidate path is absent from both the filesystem and the reserved-path set.
- Perform a complete preflight validation before making any filesystem changes, including confirming that every source still exists and every destination remains available.
- Revalidate each destination immediately before moving its source file to reduce time-of-check/time-of-use risk.
- Implement rollback handling: if any move fails, move successfully processed files back to their original paths where possible and report any rollback failures.
- Require an explicit execution option after a dry run, rather than defaulting to live changes when
-DryRunis omitted. - Add automated tests covering duplicate names across recursive subdirectories, case-only filename differences on case-insensitive filesystems, pre-existing suffixed names, and failures occurring after one or more successful moves.
