{"uuid": "d1468a0b-3c9f-4c39-a594-51b349525778", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2026-45321", "type": "seen", "source": "https://gist.github.com/Fazzani/f2627d3f340f16643f41c7cab7a6b772", "content": "# ============================================================\n# Invoke-MiniShaiHuludCheck.ps1\n# CTI Advisory #002 \u2014 CVE-2026-45321 \u2014 TLP:AMBER\n# Threat actor: TeamPCP (DeadCatx3 / PCPcat / ShellForce / CipherForce)\n# CVSS 9.6 Critical\n#\n# Validates whether REAL artefacts are present on disk \u2014\n# not just traces in PowerShell history.\n#\n# Designed to run via one-liner (Gist):\n#   Windows (PowerShell):  irm  | iex\n#   macOS / Linux:         curl -fsSL  | pwsh\n#\n# \u26a0  CRITICAL SAFETY ORDER:\n#    ISOLATE machine \u2192 IMAGE \u2192 KILL DAEMON \u2192 REVOKE secrets \u2192 ROTATE\n#    DO NOT revoke tokens before network isolation.\n#    The worm watchdog triggers data wipe on token revocation.\n# ============================================================\n\nSet-StrictMode -Version Latest\n\n# \u2500\u2500 Helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction Write-Header {\n    param([string]$Text)\n    Write-Host \"`n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\" -ForegroundColor Cyan\n    Write-Host \" $Text\" -ForegroundColor Cyan\n    Write-Host \"\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\" -ForegroundColor Cyan\n}\n\nfunction Write-Section {\n    param([string]$Text)\n    Write-Host \"`n\u2500\u2500 $Text \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\" -ForegroundColor DarkCyan\n}\n\nfunction Write-Hit {\n    param([string]$Severity, [string]$Label, [string]$Detail)\n    $color = switch ($Severity) {\n        'critical' { 'Red' }\n        'high'     { 'Yellow' }\n        default    { 'Magenta' }\n    }\n    Write-Host \"  [$(($Severity).ToUpper())] $Label\" -ForegroundColor $color\n    if ($Detail) {\n        Write-Host \"         \u2192 $Detail\" -ForegroundColor DarkGray\n    }\n}\n\nfunction Write-OK {\n    param([string]$Text)\n    Write-Host \"  [OK]  $Text\" -ForegroundColor Green\n}\n\n# \u2500\u2500 IOC Definitions \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n$PAYLOAD_FILES = @(\n    @{ Name = 'setup_bun.js';         Severity = 'critical'; Hash = $null }\n    @{ Name = 'bun_environment.js';   Severity = 'critical'; Hash = $null }\n    @{ Name = 'router_init.js';       Severity = 'critical'; Hash = 'ab4fcadaec49c03278063dd269ea5eef82d24f2124a8e15d7b90f2fa8601266c' }\n    @{ Name = 'router_runtime.js';    Severity = 'critical'; Hash = $null }\n    @{ Name = 'tanstack_runner.js';   Severity = 'critical'; Hash = '2ec78d556d696e208927cc503d48e4b5eb56b31abc2870c2ed2e98d6be27fc96' }\n)\n\n$PERSISTENCE_PATHS = @(\n    @{ RelPath = '.claude\\settings.json'; Severity = 'critical'; Label = '.claude/settings.json (modified by worm)' }\n    @{ RelPath = '.claude\\setup.mjs';     Severity = 'critical'; Label = '.claude/setup.mjs (worm dropper)' }\n    @{ RelPath = '.claude.json';          Severity = 'critical'; Label = '.claude.json (harvested by worm)' }\n    @{ RelPath = '.vscode\\tasks.json';    Severity = 'critical'; Label = '.vscode/tasks.json (modified by worm)' }\n    @{ RelPath = '.vscode\\setup.mjs';     Severity = 'critical'; Label = '.vscode/setup.mjs (worm dropper)' }\n)\n\n$SUSPICIOUS_PROCESSES = @(\n    @{ Pattern = 'gh-token-monitor'; Severity = 'critical'; Label = 'gh-token-monitor daemon (persistence)' }\n    @{ Pattern = 'tanstack';         Severity = 'critical'; Label = 'tanstack_runner process' }\n    @{ Pattern = 'router_runtime';   Severity = 'critical'; Label = 'router_runtime process' }\n)\n\n$C2_DOMAINS = @(\n    'git-tanstack.com'\n    'seed1.getsession.org'\n    'zero.masscan.cloud'\n)\n\n$SUSPICIOUS_STRINGS = @(\n    @{ Pattern = 'A Mini Shai-Hulud has Appeared';              Severity = 'critical' }\n    @{ Pattern = 'Sha1-Hulud: The Second Coming';               Severity = 'critical' }\n    @{ Pattern = 'Shai-Hulud: Here We Go Again';                Severity = 'critical' }\n    @{ Pattern = 'IfYouRevokeThisTokenItWillWipeTheComputerOfTheOwner'; Severity = 'critical' }\n    @{ Pattern = 'ctf-scramble-v2';                             Severity = 'critical' }\n    @{ Pattern = 'OhNoWhatsGoingOnWithGitHub:';                 Severity = 'critical' }\n    @{ Pattern = 'svksjrhjkcejg';                               Severity = 'critical' }\n)\n\n$COMPROMISED_PACKAGES = @(\n    '@mistralai/mistralai'\n    '@uipath/apollo-core'\n    'intercom-client@7.0.4'\n    'mbt@1.2.48'\n    '@cap-js/db-service'\n    '@cap-js/sqlite@2.2.2'\n    '@cap-js/postgres'\n)\n\n# \u2500\u2500 State \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n$findings = [System.Collections.Generic.List[hashtable]]::new()\n\nfunction Add-Finding {\n    param([string]$Severity, [string]$Category, [string]$Label, [string]$Detail = '')\n    $findings.Add(@{ Severity = $Severity; Category = $Category; Label = $Label; Detail = $Detail })\n    Write-Hit -Severity $Severity -Label $Label -Detail $Detail\n}\n\n# \u2500\u2500 Banner \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nWrite-Host @\"\n`n\n  \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557\n  \u2551   Mini Shai-Hulud \u2014 Artefact Verification                   \u2551\n  \u2551   CTI Advisory #002 \u00b7 CVE-2026-45321 \u00b7 TLP:AMBER            \u2551\n  \u2551                                                              \u2551\n  \u2551   \u26a0  ISOLATE machine BEFORE revoking any token/secret  \u26a0   \u2551\n  \u255a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255d\n\"@ -ForegroundColor DarkYellow\n\n$auditDate = (Get-Date -Format 'yyyy-MM-ddTHH:mm:ssZ')\n$hostname  = $env:COMPUTERNAME\nWrite-Host \"  Host   : $hostname\" -ForegroundColor Gray\nWrite-Host \"  Date   : $auditDate\" -ForegroundColor Gray\nWrite-Host \"  User   : $($env:USERNAME)`n\" -ForegroundColor Gray\n\n# \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n# 1. PAYLOAD FILES ON DISK\n# \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\nWrite-Header \"1/5 \u2014 Payload files on disk\"\n\n$searchRoots = @(\n    $env:USERPROFILE\n    $env:APPDATA\n    $env:LOCALAPPDATA\n    $env:TEMP\n    [System.IO.Path]::GetTempPath()\n    'C:\\ProgramData'\n) | Where-Object { $_ -and (Test-Path $_) } | Sort-Object -Unique\n\nforeach ($payload in $PAYLOAD_FILES) {\n    $found = $false\n    foreach ($root in $searchRoots) {\n        try {\n            $matches_ = Get-ChildItem -Path $root -Recurse -Filter $payload.Name `\n                -ErrorAction SilentlyContinue -Force 2&gt;$null\n            foreach ($f in $matches_) {\n                $found = $true\n                $detail = $f.FullName\n\n                # SHA-256 verification\n                if ($payload.Hash) {\n                    try {\n                        $actual = (Get-FileHash $f.FullName -Algorithm SHA256).Hash.ToLower()\n                        if ($actual -eq $payload.Hash) {\n                            $detail = \"$($f.FullName) \u2014 HASH CONFIRMED malicious ($actual)\"\n                        } else {\n                            $detail = \"$($f.FullName) \u2014 hash mismatch (actual: $actual)\"\n                            # File exists but hash differs \u2014 still suspicious, treat as high\n                        }\n                    } catch { $detail = \"$($f.FullName) \u2014 could not hash file\" }\n                }\n\n                Add-Finding -Severity $payload.Severity `\n                            -Category 'filesystem' `\n                            -Label    \"$($payload.Name) found on disk\" `\n                            -Detail   $detail\n            }\n        } catch { &lt;# silently skip inaccessible dirs #&gt; }\n    }\n    if (-not $found) {\n        Write-OK \"$($payload.Name) \u2014 not found on disk\"\n    }\n}\n\n# Special case: Linux payload (running via WSL or cross-platform)\nif (Test-Path '/tmp/transformers.pyz' -ErrorAction SilentlyContinue) {\n    Add-Finding -Severity 'critical' -Category 'filesystem' `\n                -Label '/tmp/transformers.pyz (PyPI mistralai payload)' `\n                -Detail '/tmp/transformers.pyz'\n} else {\n    Write-OK \"/tmp/transformers.pyz \u2014 not found\"\n}\n\n# \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n# 2. PERSISTENCE ARTEFACTS\n# \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\nWrite-Header \"2/5 \u2014 Persistence artefacts\"\n\nforeach ($p in $PERSISTENCE_PATHS) {\n    $fullPath = Join-Path $env:USERPROFILE $p.RelPath\n    if (Test-Path $fullPath -ErrorAction SilentlyContinue) {\n        Add-Finding -Severity $p.Severity -Category 'persistence' `\n                    -Label $p.Label -Detail $fullPath\n    } else {\n        Write-OK \"$($p.Label) \u2014 not found\"\n    }\n}\n\n# \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n# 3. PROCESSES\n# \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\nWrite-Header \"3/5 \u2014 Running processes\"\n\nforeach ($proc in $SUSPICIOUS_PROCESSES) {\n    $running = Get-Process -ErrorAction SilentlyContinue | Where-Object {\n        $_.ProcessName -match $proc.Pattern -or\n        ($_.MainModule -and $_.MainModule.FileName -match $proc.Pattern)\n    }\n    if ($running) {\n        foreach ($r in $running) {\n            Add-Finding -Severity $proc.Severity -Category 'process' `\n                        -Label $proc.Label `\n                        -Detail \"PID=$($r.Id)  Name=$($r.ProcessName)\"\n        }\n    } else {\n        Write-OK \"$($proc.Label) \u2014 not running\"\n    }\n}\n\n# gh-token-monitor via scheduled task\nWrite-Section \"Scheduled tasks\"\ntry {\n    $tasks = Get-ScheduledTask -ErrorAction SilentlyContinue |\n             Where-Object { $_.TaskName -match 'bun|tanstack|router|gh-token|monitor' }\n    if ($tasks) {\n        foreach ($t in $tasks) {\n            Add-Finding -Severity 'critical' -Category 'persistence' `\n                        -Label \"Suspicious scheduled task: $($t.TaskName)\" `\n                        -Detail $t.TaskPath\n        }\n    } else {\n        Write-OK \"No suspicious scheduled tasks found\"\n    }\n} catch {\n    Write-Host \"  [INFO] Could not query scheduled tasks: $_\" -ForegroundColor DarkGray\n}\n\n# \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n# 4. NETWORK \u2014 Active connections to C2 domains\n# \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\nWrite-Header \"4/5 \u2014 Active network connections to C2\"\n\n$tcpConnections = Get-NetTCPConnection -ErrorAction SilentlyContinue\nforeach ($domain in $C2_DOMAINS) {\n    try {\n        $resolved = [System.Net.Dns]::GetHostAddresses($domain) | Select-Object -ExpandProperty IPAddressToString\n    } catch { $resolved = @() }\n\n    $hit = $tcpConnections | Where-Object {\n        $resolved -contains $_.RemoteAddress\n    }\n    if ($hit) {\n        foreach ($c in $hit) {\n            Add-Finding -Severity 'critical' -Category 'network' `\n                        -Label \"Active connection to C2: $domain\" `\n                        -Detail \"Local=$($c.LocalAddress):$($c.LocalPort)  Remote=$($c.RemoteAddress):$($c.RemotePort)  PID=$($c.OwningProcess)\"\n        }\n    } else {\n        Write-OK \"$domain \u2014 no active connection\"\n    }\n}\n\n# \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n# 5. SUSPICIOUS STRINGS in .json / .js / .mjs / .lock / .txt files\n#    (limited to user profile \u2014 not full disk scan)\n# \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\nWrite-Header \"5/5 \u2014 Suspicious strings in config / source files\"\n\n$stringScanExtensions = @('*.json', '*.js', '*.mjs', '*.lock', '*.txt', '*.yml', '*.yaml')\n$stringScanRoots = @(\n    $env:USERPROFILE\n    $env:APPDATA\n    $env:LOCALAPPDATA\n) | Where-Object { $_ -and (Test-Path $_) } | Sort-Object -Unique\n\n# Build one combined regex for efficiency\n$combinedPattern = ($SUSPICIOUS_STRINGS | ForEach-Object { [Regex]::Escape($_.Pattern) }) -join '|'\n$combinedRegex   = [System.Text.RegularExpressions.Regex]::new($combinedPattern, [System.Text.RegularExpressions.RegexOptions]::IgnoreCase)\n\n# Track found strings to avoid duplicate reporting per string\n$foundStrings = @{}\n\nforeach ($root in $stringScanRoots) {\n    foreach ($ext in $stringScanExtensions) {\n        try {\n            $files = Get-ChildItem -Path $root -Recurse -Filter $ext `\n                -ErrorAction SilentlyContinue -Force 2&gt;$null |\n                Where-Object { $_.Length -lt 5MB }  # skip huge files\n            foreach ($f in $files) {\n                try {\n                    $content = [System.IO.File]::ReadAllText($f.FullName, [System.Text.Encoding]::UTF8)\n                    $m = $combinedRegex.Match($content)\n                    if ($m.Success) {\n                        $key = \"$($f.FullName)|$($m.Value)\"\n                        if (-not $foundStrings.ContainsKey($key)) {\n                            $foundStrings[$key] = $true\n                            $ioc = $SUSPICIOUS_STRINGS | Where-Object {\n                                $content -imatch [Regex]::Escape($_.Pattern)\n                            } | Select-Object -First 1\n                            Add-Finding -Severity ($ioc ? $ioc.Severity : 'critical') `\n                                        -Category 'string' `\n                                        -Label \"Campaign marker found: `\"$($m.Value)`\"\" `\n                                        -Detail $f.FullName\n                        }\n                    }\n                } catch { &lt;# skip unreadable files #&gt; }\n            }\n        } catch { &lt;# skip inaccessible dirs #&gt; }\n    }\n}\n\n# Check compromised packages in package.json / package-lock.json\nWrite-Section \"Compromised packages in package.json\"\n$pkgFiles = Get-ChildItem -Path $env:USERPROFILE -Recurse -ErrorAction SilentlyContinue `\n    -Include 'package.json','package-lock.json' -Force 2&gt;$null |\n    Where-Object { $_.Length -lt 2MB -and $_.FullName -notmatch '\\\\node_modules\\\\' }\n\n$pkgHits = @{}\nforeach ($f in $pkgFiles) {\n    try {\n        $raw = [System.IO.File]::ReadAllText($f.FullName)\n        foreach ($pkg in $COMPROMISED_PACKAGES) {\n            if ($raw -imatch [Regex]::Escape($pkg)) {\n                $key = \"$($f.FullName)|$pkg\"\n                if (-not $pkgHits.ContainsKey($key)) {\n                    $pkgHits[$key] = $true\n                    Add-Finding -Severity 'critical' -Category 'package' `\n                                -Label \"Compromised package referenced: $pkg\" `\n                                -Detail $f.FullName\n                }\n            }\n        }\n    } catch { &lt;# skip #&gt; }\n}\n\nif ($pkgHits.Count -eq 0) {\n    Write-OK \"No compromised packages found in package.json files\"\n}\n\n# \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n# SUMMARY\n# \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\nWrite-Header \"SUMMARY \u2014 $hostname \u2014 $auditDate\"\n\n$criticalCount = ($findings | Where-Object { $_.Severity -eq 'critical' }).Count\n$highCount     = ($findings | Where-Object { $_.Severity -eq 'high' }).Count\n$total         = $findings.Count\n\nif ($total -eq 0) {\n    Write-Host \"`n  \u2714  NO ARTEFACTS FOUND \u2014 Likely false positive.\" -ForegroundColor Green\n    Write-Host \"     The previous report matched only command-history traces, not real files.\" -ForegroundColor Gray\n    Write-Host \"     Recommended: keep monitoring, no immediate escalation required.`n\" -ForegroundColor Gray\n} else {\n    Write-Host \"`n  \u2718  $total finding(s): $criticalCount CRITICAL, $highCount HIGH\" -ForegroundColor Red\n    Write-Host \"\"\n\n    if ($criticalCount -gt 0) {\n        Write-Host \"  MANDATORY INCIDENT RESPONSE ORDER:\" -ForegroundColor Red\n        Write-Host \"   1. ISOLATE the machine from the network NOW (do not revoke tokens yet)\" -ForegroundColor Yellow\n        Write-Host \"   2. PRESERVE evidence \u2014 do not reboot, do not delete files\" -ForegroundColor Yellow\n        Write-Host \"   3. IMAGE the disk if possible\" -ForegroundColor Yellow\n        Write-Host \"   4. KILL the gh-token-monitor daemon (if running)\" -ForegroundColor Yellow\n        Write-Host \"   5. THEN revoke and rotate all exposed secrets\" -ForegroundColor Yellow\n        Write-Host \"   6. ESCALATE to CSIRT with this output and the CSV report\" -ForegroundColor Yellow\n    }\n\n    Write-Host \"`n  Findings detail:\" -ForegroundColor DarkYellow\n    foreach ($f in $findings) {\n        $color = if ($f.Severity -eq 'critical') { 'Red' } elseif ($f.Severity -eq 'high') { 'Yellow' } else { 'Magenta' }\n        Write-Host \"    [$($f.Severity.ToUpper())][$($f.Category)] $($f.Label)\" -ForegroundColor $color\n        if ($f.Detail) {\n            Write-Host \"       $($f.Detail)\" -ForegroundColor DarkGray\n        }\n    }\n    Write-Host \"\"\n}\n", "creation_timestamp": "2026-05-19T12:35:06.000000Z"}