<?xml version='1.0' encoding='UTF-8'?>
<?xml-stylesheet href="/static/style.xsl" type="text/xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
  <id>https://vulnerability.circl.lu/sightings/feed</id>
  <title>Most recent sightings.</title>
  <updated>2026-06-06T17:45:10.407719+00:00</updated>
  <author>
    <name>Vulnerability-Lookup</name>
    <email>info@circl.lu</email>
  </author>
  <link href="https://vulnerability.circl.lu" rel="alternate"/>
  <generator uri="https://lkiesow.github.io/python-feedgen" version="1.0.0">python-feedgen</generator>
  <subtitle>Contains only the most 10 recent sightings.</subtitle>
  <entry>
    <id>https://vulnerability.circl.lu/sighting/1fcf8dfe-5d6a-4d79-bfd4-a7e767eea191/export</id>
    <title>1fcf8dfe-5d6a-4d79-bfd4-a7e767eea191</title>
    <updated>2026-06-06T17:45:10.837111+00:00</updated>
    <author>
      <name>Automation user</name>
      <uri>https://vulnerability.circl.lu/user/automation</uri>
    </author>
    <content>{"uuid": "1fcf8dfe-5d6a-4d79-bfd4-a7e767eea191", "vulnerability_lookup_origin": "405284c2-e461-4670-8979-7fd2c9755a60", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2026-48027", "type": "exploited", "source": "https://vulnerability.circl.lu/known-exploited-vulnerabilities-catalog/23d94b6e-e10b-4ed3-9304-fbf1858a9ac5", "content": "", "creation_timestamp": "2026-05-27T18:00:02.229951Z"}</content>
    <link href="https://vulnerability.circl.lu/sighting/1fcf8dfe-5d6a-4d79-bfd4-a7e767eea191/export"/>
    <published>2026-05-27T18:00:02.229951+00:00</published>
  </entry>
  <entry>
    <id>https://vulnerability.circl.lu/sighting/1b8c7fe8-d62f-4b80-815a-94a3f2ce4d2a/export</id>
    <title>1b8c7fe8-d62f-4b80-815a-94a3f2ce4d2a</title>
    <updated>2026-06-06T17:45:10.837007+00:00</updated>
    <author>
      <name>Automation user</name>
      <uri>https://vulnerability.circl.lu/user/automation</uri>
    </author>
    <content>{"uuid": "1b8c7fe8-d62f-4b80-815a-94a3f2ce4d2a", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2026-48027", "type": "seen", "source": "https://bsky.app/profile/cvesentinel.bsky.social/post/3mmu45p54pa2c", "content": "\ud83d\uded1 CVE-2026-48027\nNx Nx Console\nCVSS 9.3 / KEV\nTL;DR: Nx Console is the user interface for Nx &amp;amp; Lerna. On 19 May 2026, a malicious version of Nx Console, 18.95.0\u2026\nhttps://cvesentinel.com/report/CVE-2026-48027?utm_source=bluesky&amp;amp;utm_medium=social&amp;amp;utm_campaign=cvesentinel\n#infosec #CVE #vulnerability", "creation_timestamp": "2026-05-27T18:10:41.545491Z"}</content>
    <link href="https://vulnerability.circl.lu/sighting/1b8c7fe8-d62f-4b80-815a-94a3f2ce4d2a/export"/>
    <published>2026-05-27T18:10:41.545491+00:00</published>
  </entry>
  <entry>
    <id>https://vulnerability.circl.lu/sighting/2d594745-8ea2-4456-85fc-b959da64566c/export</id>
    <title>2d594745-8ea2-4456-85fc-b959da64566c</title>
    <updated>2026-06-06T17:45:10.836902+00:00</updated>
    <author>
      <name>Automation user</name>
      <uri>https://vulnerability.circl.lu/user/automation</uri>
    </author>
    <content>{"uuid": "2d594745-8ea2-4456-85fc-b959da64566c", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2026-48027", "type": "seen", "source": "https://feedsin.space/feed/CISAKevBot/items/6591185", "content": "2026-05-27: [CVE-2026-48027] Nx Console Embedded Malicious Code VulnerabilityNx Console contains an embedded malicious code vulnerability that allowed a malicious version of Nx Console to be published. The compromised extension fetched an obfuscated payload that could harvested credentials from multiple sources on disk and in memory.\ncisakev", "creation_timestamp": "2026-05-27T19:09:46.684896Z"}</content>
    <link href="https://vulnerability.circl.lu/sighting/2d594745-8ea2-4456-85fc-b959da64566c/export"/>
    <published>2026-05-27T19:09:46.684896+00:00</published>
  </entry>
  <entry>
    <id>https://vulnerability.circl.lu/sighting/e1fb8098-2cc8-4a4d-be3e-5c4533d079e0/export</id>
    <title>e1fb8098-2cc8-4a4d-be3e-5c4533d079e0</title>
    <updated>2026-06-06T17:45:10.836795+00:00</updated>
    <author>
      <name>Automation user</name>
      <uri>https://vulnerability.circl.lu/user/automation</uri>
    </author>
    <content>{"uuid": "e1fb8098-2cc8-4a4d-be3e-5c4533d079e0", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2026-48027", "type": "seen", "source": "https://bsky.app/profile/boredchilada.bsky.social/post/3mmucnfq3w323", "content": "~Cisa~\nCISA added three actively exploited vulnerabilities to the KEV catalog.\n-\nIOCs: CVE-2026-8398, CVE-2026-45321, CVE-2026-48027\n-\n#CISA #KEV #threatintel", "creation_timestamp": "2026-05-27T20:06:47.890100Z"}</content>
    <link href="https://vulnerability.circl.lu/sighting/e1fb8098-2cc8-4a4d-be3e-5c4533d079e0/export"/>
    <published>2026-05-27T20:06:47.890100+00:00</published>
  </entry>
  <entry>
    <id>https://vulnerability.circl.lu/sighting/d9533387-13a8-4f9b-b26b-f2a5b2c10e7d/export</id>
    <title>d9533387-13a8-4f9b-b26b-f2a5b2c10e7d</title>
    <updated>2026-06-06T17:45:10.836676+00:00</updated>
    <author>
      <name>Automation user</name>
      <uri>https://vulnerability.circl.lu/user/automation</uri>
    </author>
    <content>{"uuid": "d9533387-13a8-4f9b-b26b-f2a5b2c10e7d", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2026-48027", "type": "seen", "source": "https://infosec.exchange/users/vuldb/statuses/116650418837390666", "content": "A lot of offensive activities were identified targeting nrwl nx-console (CVE-2026-48027) https://vuldb.com/vuln/366456/cti", "creation_timestamp": "2026-05-28T04:55:35.601051Z"}</content>
    <link href="https://vulnerability.circl.lu/sighting/d9533387-13a8-4f9b-b26b-f2a5b2c10e7d/export"/>
    <published>2026-05-28T04:55:35.601051+00:00</published>
  </entry>
  <entry>
    <id>https://vulnerability.circl.lu/sighting/8022ecd9-db2c-41e8-92e4-449d91ebbb1d/export</id>
    <title>8022ecd9-db2c-41e8-92e4-449d91ebbb1d</title>
    <updated>2026-06-06T17:45:10.836486+00:00</updated>
    <author>
      <name>Automation user</name>
      <uri>https://vulnerability.circl.lu/user/automation</uri>
    </author>
    <content>{"uuid": "8022ecd9-db2c-41e8-92e4-449d91ebbb1d", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2026-48027", "type": "seen", "source": "https://gist.github.com/SyniRon/cdda0394ff4794c6f9936a8dda204208", "content": "# Take control of VS Code updates (without going dark on them)\n\nAuto-updating extensions is a real supply-chain risk: a compromised publisher account or a malicious release can push code straight onto your machine the moment it's published, before anyone has had a chance to notice it's bad.\n\nThis isn't hypothetical. In **[CISA's May 2026 alert](https://www.cisa.gov/news-events/alerts/2026/05/28/supply-chain-compromises-impact-nx-console-and-github-repositories)**, a malicious build of the **Nx Console VS Code extension (v18.95.0, [CVE-2026-48027](https://www.cisa.gov/known-exploited-vulnerabilities-catalog))** was, in CISA's words, *\"distributed through VS Code's automatic update mechanism, meaning systems with Nx Console previously installed may have received the malicious build without developers taking any manual installation action.\"* It was used to exfiltrate internal GitHub repositories. Auto-update was the delivery vehicle.\n\nThe fix is **not** to bury your head and never update. That leaves you on known-vulnerable versions. The right posture is:\n\n&amp;gt; **Don't auto-install. Stay notified. Update deliberately, after a release has had a few days to be vetted.**\n\nThis gist sets VS Code up that way.\n\n## The threat model in one line\n\n- **The editor itself** (VS Code) is signed by Microsoft and ships security patches, so you generally *want* these, just on your terms, not mid-session.\n- **Extensions** are third-party code from the Marketplace. This is where the supply-chain risk lives. Auto-update here means \"run whatever a publisher uploaded, instantly.\" That's the setting to kill.\n\n---\n\n## TL;DR settings\n\nOpen `settings.json` (`Cmd/Ctrl+Shift+P` \u2192 **Preferences: Open User Settings (JSON)**):\n\n```jsonc\n{\n  // --- App: get notified on startup, but never silently install ---\n  \"update.mode\": \"start\",\n\n  // --- Extensions: the important one ---\n  \"extensions.autoUpdate\": false,       // never auto-install extension updates\n  \"extensions.autoCheckUpdates\": true,  // DO check + show the badge so you know they exist\n  \"extensions.showRecommendationsOnlyOnDemand\": false\n}\n```\n\nThe key combination is `autoUpdate: false` + `autoCheckUpdates: true`: nothing installs on its own, but you still see the \"update available\" badge and per-extension **Update** buttons. You decide when.\n\n---\n\n## App updates: notified, not forced\n\n`update.mode` controls the editor itself:\n\n| Value       | Behavior                                                                 | Good for |\n|-------------|--------------------------------------------------------------------------|----------|\n| `\"default\"` | Auto-checks in the background, downloads, prompts to restart.            | Most people |\n| `\"start\"`   | Checks **only on startup**, then notifies. No background nagging.        | **Recommended here** |\n| `\"manual\"`  | No checks at all; you must run *Check for Updates* yourself.             | Fully air-gapped habits |\n| `\"none\"`    | Disables updates entirely.                                               | Not recommended |\n\n`\"start\"` is the sweet spot: you learn an update exists when you open VS Code, but it never installs without you clicking **Restart to Update**. Because the editor is Microsoft-signed, it's reasonable to apply these fairly promptly, since they're often security fixes.\n\nManual check anytime: **Code \u2192 Check for Updates\u2026** (macOS) / **Help \u2192 Check for Updates\u2026** (Win/Linux).\n\n---\n\n## Extension updates: the part that matters\n\nTwo settings work together:\n\n- **`extensions.autoUpdate: false`**: extensions never update themselves. *This is the security control.*\n- **`extensions.autoCheckUpdates: true`**: VS Code still checks and flags outdated extensions, so you're not flying blind.\n\nResult: the Extensions icon shows an update badge, and each outdated extension gets an **Update** button, but **nothing runs until you click it.**\n\n### Same thing via the UI\n\n1. Open **Extensions** (`Cmd/Ctrl+Shift+X`).\n2. Click the **`...`** (Views and More Actions) menu at the top.\n3. Turn **Auto Update Extensions** off.\n\n### Pin critical extensions to a known-good version\n\nFor anything sensitive (linters, formatters, anything that runs on save, anything with broad filesystem/network access), lock the exact version:\n\n- Right-click the extension \u2192 **Install Another Version\u2026** \u2192 pick a version you trust.\n\nIt stays on that version even when an update appears, until you deliberately move it.\n\n---\n\n## A 30-second checklist before you click Update\n\nThis is where the actual safety comes from. When you see an update available:\n\n1. **Let it bake.** Don't update the moment a release drops. That's exactly when a poisoned build does its damage. CISA's floor for packages is *at least 3 hours*; for extensions you lose almost nothing by waiting days, which is plenty of time for a malicious release to be caught and pulled.\n2. **Check the changelog / release notes.** Unexplained version jumps or a vague \"bug fixes\" on a big version bump is a yellow flag.\n3. **Confirm the publisher is unchanged and verified.** A new or changed publisher on an established extension is a red flag; publisher-account compromise is a common vector.\n4. **Glance at the Marketplace page.** Recent reviews and the issue tracker often surface \"this update broke / looks sketchy\" fast.\n5. **Prefer batching.** Review and apply updates on a schedule (e.g. weekly), not reflexively per popup.\n\n&amp;gt; These mirror CISA's package-repo guidance from the same alert: **wait before pulling a new release, pin to trusted versions, and only install from sources you trust.**\n\n---\n\n## Verify it stuck\n\nReload the window (`Cmd/Ctrl+Shift+P` \u2192 **Developer: Reload Window**), reopen Settings, and confirm the values. You should still see update badges (that's intended), but nothing should install without your click.\n\n---\n\n### Quick reference\n\n```jsonc\n{\n  \"update.mode\": \"start\",               // notified on startup, manual install\n  \"extensions.autoUpdate\": false,       // no auto-install of extensions\n  \"extensions.autoCheckUpdates\": true   // but DO tell me updates exist\n}\n```\n", "creation_timestamp": "2026-06-03T21:32:05.000000Z"}</content>
    <link href="https://vulnerability.circl.lu/sighting/8022ecd9-db2c-41e8-92e4-449d91ebbb1d/export"/>
    <published>2026-06-03T21:32:05+00:00</published>
  </entry>
  <entry>
    <id>https://vulnerability.circl.lu/sighting/d02969f5-992e-429c-ae22-f486c16497aa/export</id>
    <title>d02969f5-992e-429c-ae22-f486c16497aa</title>
    <updated>2026-06-06T17:45:10.835744+00:00</updated>
    <author>
      <name>Automation user</name>
      <uri>https://vulnerability.circl.lu/user/automation</uri>
    </author>
    <content>{"uuid": "d02969f5-992e-429c-ae22-f486c16497aa", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2026-48027", "type": "seen", "source": "https://gist.github.com/FedericoGarcia/803c3ac4e3d93b4042dcd135a43c5a4c", "content": "# Supply Chain Malware Scanner\n\nAutomated scanner for known supply chain malware targeting JavaScript/Node.js projects. Designed for team-wide compromise assessment \u2014 run it on every developer machine to triage quickly.\n\n**Read-only** \u2014 these scripts do not modify files, install packages, or change system state.\n**Safe** \u2014 credential/token values are never printed in the output. Only existence is reported.\n\n## Threats covered\n\n| Threat | Vector | Impact |\n|--------|--------|--------|\n| **PolinRider** (Lazarus/DPRK) | Malicious npm packages with `postinstall` hooks inject obfuscated code into JS config files | Credential theft, SSH keys, env vars, browser data, crypto wallets |\n| **InvisibleFerret** | Second-stage RAT deployed by PolinRider | Persistent remote access, full system compromise |\n| **Megalodon** | Compromised GitHub Actions workflows (5,500+ repos, May 2026) | CI/CD pipeline injection, secret exfiltration |\n| **Nx Console CVE-2026-48027** | Compromised VS Code extension v18.95.0 | Code execution via trusted extension |\n| **axios 1.14.1 / 0.30.4** | Compromised maintainer account (March 2026) | Backdoored HTTP client library |\n\n## What it checks (20 checks + optional deep scan)\n\n### Core IOCs (1-4) \u2014 direct compromise evidence\n1. Lock file (`/tmp/tmp7A863DD1.tmp`) \u2014 if present, the payload executed\n2. Credential dumps in `~/.npm/` \u2014 staging directory for exfiltrated data\n3. Active network connections to known C2 IPs\n4. InvisibleFerret RAT processes\n\n### Source code infection (5-10)\n5. Known malware signatures (obfuscated variable names, encoded strings)\n6. Suspiciously long lines in config files (payload hides after ~1300 spaces)\n7. Fake `.woff2` font files containing JavaScript\n8. Malicious npm packages in `package.json`\n9. VS Code `tasks.json` with C2 domain references\n10. Solana/blockchain C2 communication patterns\n\n### Supply chain (11-13)\n11. Compromised axios versions (1.14.1, 0.30.4)\n12. Nx Console extension CVE-2026-48027\n13. Suspicious `postinstall`/`preinstall` scripts\n\n### Propagation (14-15)\n14. `.bat` files used to rewrite git history silently\n15. Megalodon-style `curl|bash` patterns in GitHub Actions\n\n### Environment integrity (16-20)\n16. Git hooks \u2014 global `core.hooksPath` hijacking\n17. `.npmrc` auth tokens \u2014 existence count (values never printed)\n18. Global npm/pnpm packages inventory\n19. VS Code/Cursor extensions inventory\n20. Persistence mechanisms (LaunchAgents, cron, running processes)\n\n### Deep scan (optional, slow)\n- **macOS:** DNS queries and system log entries referencing C2 domains (last 7 days)\n- **Windows:** Security Event Log network and process creation events (requires Admin)\n\n## Usage\n\n### macOS / Linux\n\n```bash\nchmod +x scan-supply-chain.sh\n\n# Standard scan\n./scan-supply-chain.sh\n\n# With deep log analysis (adds 1-2 minutes on macOS)\n./scan-supply-chain.sh --deep\n\n# Custom source code directories\n./scan-supply-chain.sh --scan-dirs \"$HOME/work $HOME/personal\"\n\n# Or via environment variable\nSCAN_DIRS=\"$HOME/work $HOME/personal\" ./scan-supply-chain.sh\n```\n\n### Windows (PowerShell)\n\n```powershell\n# Standard scan\n.\\Scan-SupplyChain.ps1\n\n# With deep Event Log analysis (requires Admin)\n.\\Scan-SupplyChain.ps1 -Deep\n\n# Custom directories\n.\\Scan-SupplyChain.ps1 -ScanDirs \"C:\\code\", \"D:\\projects\"\n```\n\n**Note:** The `-Deep` flag on Windows reads the Security Event Log, which requires an elevated (Admin) PowerShell session.\n\n## Default scan directories\n\nThe scanner checks these directories if they exist:\n\n| macOS/Linux | Windows |\n|-------------|---------|\n| `~/git` | `%USERPROFILE%\\git` |\n| `~/projects` | `%USERPROFILE%\\projects` |\n| `~/dev` | `%USERPROFILE%\\dev` |\n| `~/code` | `%USERPROFILE%\\code` |\n| `~/repos` | `%USERPROFILE%\\repos` |\n| | `%USERPROFILE%\\source` |\n\nOverride with `--scan-dirs` (bash) or `-ScanDirs` (PowerShell) if your code lives elsewhere.\n\n## Reading results\n\n### Summary table\n\nThe script ends with a summary table:\n\n```\n #   Check                               Result\n --- ----------------------------------- ------\n   1 Lock file                           \u2705\n   2 Credential dumps                    \u2705\n   3 C2 connections                      \u2705\n   ...\n```\n\n### Severity levels\n\n| Icon | Meaning | Action |\n|------|---------|--------|\n| \u2705 | Clean | No action needed |\n| \u23ed\ufe0f | Skipped | Directory not found or tool not available |\n| \ud83d\udc40 | Informational | Review briefly for anything unexpected |\n| \u26a0\ufe0f | Suspicious | Needs manual verification \u2014 may be a false positive |\n| \ud83d\udd34 | Confirmed IOC | **Stop all work. Do not push. Report immediately.** |\n\n### If you get any \ud83d\udd34 finding\n\n1. **Do not push** to any repository\n2. **Do not delete** evidence files \u2014 they're needed for forensics\n3. **Report** to your security lead with the full script output\n4. **Rotate** all secrets: npm tokens, SSH keys, GitHub PATs, API keys, `.env` values\n5. **Check** browser saved passwords \u2014 InvisibleFerret steals them\n\n### If you only get \u26a0\ufe0f findings\n\nReview each one manually. Common false positives:\n- **Blockchain C2 patterns**: legitimate if the project uses Solana/Tron\n- **Long config lines**: some bundled configs legitimately have long lines \u2014 check if the length comes from trailing spaces (malware) or actual code\n- **postinstall scripts**: `node scripts/setup.js` is normal for many projects \u2014 verify the script content\n- **.npmrc tokens**: expected if you publish to private registries \u2014 but rotate them if any \ud83d\udd34 was found\n\n## Exit codes\n\n- `0` \u2014 no findings (clean)\n- `1` \u2014 one or more findings detected\n\n## Limitations\n\nThis scanner checks for **known IOCs** from specific campaigns. It does not:\n\n- Detect novel/zero-day supply chain attacks\n- Monitor runtime behavior or network traffic\n- Replace endpoint detection and response (EDR) tools\n- Scan compiled/minified bundles (only source and config files)\n- Verify git history integrity (use `git log --diff-filter=M -- '*.config.*'` separately)\n\nA clean scan is good news but not proof of absence. Keep your EDR active and dependencies audited.\n\n## References\n\n- [CISA Alert \u2014 Supply Chain Compromises](https://www.cisa.gov/news-events/alerts/2026/05/28/supply-chain-compromises-impact-nx-console-and-github-repositories)\n- [PolinRider analysis](https://github.com/nicolo-ribaudo/malware-analysis/tree/main/nicolo-ribaudo/2025-06-PolinRider)\n- [Nx Console CVE-2026-48027](https://nvd.nist.gov/vuln/detail/CVE-2026-48027)\n- [Megalodon GitHub Actions campaign](https://socket.dev/blog/megalodon-github-actions-supply-chain-attack)\n\n\n#Requires -Version 5.1\n&amp;lt;#\n.SYNOPSIS\n    Supply Chain Malware Scanner \u2014 Windows edition\n.DESCRIPTION\n    Scans for PolinRider, InvisibleFerret, Megalodon, and compromised npm packages.\n    Read-only: does NOT modify any files or system state.\n    Safe: never prints credential or token values.\n.PARAMETER ScanDirs\n    Directories to scan for source code. Default: common locations under $HOME.\n.PARAMETER Deep\n    Enable slow Event Log checks (Security log network/process events).\n.EXAMPLE\n    .\\Scan-SupplyChain.ps1\n    .\\Scan-SupplyChain.ps1 -Deep\n    .\\Scan-SupplyChain.ps1 -ScanDirs \"C:\\code\", \"D:\\projects\"\n#&amp;gt;\n[CmdletBinding()]\nparam(\n    [string[]]$ScanDirs,\n    [switch]$Deep\n)\n\n$ErrorActionPreference = \"Continue\"\n$Version = \"1.0.0\"\n\n# \u2500\u2500\u2500 Configuration \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$DefaultScanDirs = @(\n    \"$env:USERPROFILE\\git\",\n    \"$env:USERPROFILE\\projects\",\n    \"$env:USERPROFILE\\dev\",\n    \"$env:USERPROFILE\\code\",\n    \"$env:USERPROFILE\\repos\",\n    \"$env:USERPROFILE\\source\"\n)\n\nif (-not $ScanDirs) { $ScanDirs = $DefaultScanDirs }\n$ResolvedDirs = $ScanDirs | Where-Object { Test-Path $_ }\n\n$MaxDepth = 6\n\n$C2Ips = @(\"166.88.54.158\")\n$C2DomainsRegex = \"trongrid|aptoslabs|bsc-dataseed|bsc-rpc\\.publicnode|api\\.telegram\\.org\"\n$C2VercelRegex = \"default-configuration\\.vercel|vscode-settings-bootstrap\\.vercel|vscode-load-config\\.vercel|260120\\.vercel\"\n$MaliciousPkgsRegex = \"tailwindcss-style-animate|tailwind-mainanimation|tailwind-tionbased|tailwindcss-typography-style|tailwindcss-style-modify|tailwindcss-animate-style\"\n\n$ExcludeDirs = @(\"node_modules\", \".next\", \"dist\", \".git\", \"build\", \".turbo\", \".cache\")\n\n# \u2500\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$script:CheckNames = @()\n$script:CheckResults = @()\n$script:Findings = 0\n$script:Current = 0\n$script:TotalChecks = 20\n\n# \u2500\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\u2500\n\nfunction Write-Header($text) {\n    $script:Current++\n    Write-Host \"\"\n    Write-Host \"[$($script:Current)/$($script:TotalChecks)] $text\" -ForegroundColor Cyan\n}\n\nfunction Write-Pass($text)   { Write-Host \"       \u2705 $text\" -ForegroundColor Green }\nfunction Write-Warn($text)   { Write-Host \"       \u26a0\ufe0f  $text\" -ForegroundColor Yellow; $script:Findings++ }\nfunction Write-Fail($text)   { Write-Host \"       \ud83d\udd34 $text\" -ForegroundColor Red; $script:Findings++ }\nfunction Write-Detail($text) { Write-Host \"          $text\" -ForegroundColor DarkGray }\n\nfunction Record($name, $result) {\n    $script:CheckNames += $name\n    $script:CheckResults += $result\n}\n\nfunction Get-SourceFiles {\n    param([string]$Pattern, [string[]]$Include)\n    $results = @()\n    foreach ($dir in $ResolvedDirs) {\n        Get-ChildItem -Path $dir -Recurse -File -Include $Include -ErrorAction SilentlyContinue |\n            Where-Object {\n                $path = $_.FullName\n                -not ($ExcludeDirs | Where-Object { $path -match \"[\\\\/]$_[\\\\/]\" })\n            } |\n            Select-String -Pattern $Pattern -List -ErrorAction SilentlyContinue |\n            ForEach-Object { $results += $_.Path }\n    }\n    return $results\n}\n\n# \u2500\u2500\u2500 Checks \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\nfunction Test-LockFile {\n    Write-Header \"Lock file (payload execution marker)\"\n    $lockFile = \"$env:LOCALAPPDATA\\Temp\\tmp7A863DD1.tmp\"\n    if (Test-Path $lockFile) {\n        Write-Fail \"LOCK FILE EXISTS at $lockFile \u2014 payload executed\"\n        Write-Detail (Get-Item $lockFile | Format-List | Out-String)\n        Record \"Lock file\" \"\ud83d\udd34\"\n    } else {\n        Write-Pass \"Not found\"\n        Record \"Lock file\" \"\u2705\"\n    }\n}\n\nfunction Test-CredentialDumps {\n    Write-Header \"Credential dumps (~/.npm staging)\"\n    $npmDir = \"$env:USERPROFILE\\.npm\"\n    $suspicious = @(\"_credentials.json\", \"_sysenv.json\", \"_sysenv.env\", \"_info.json\")\n\n    $found = @()\n    if (Test-Path $npmDir) {\n        $found += Get-ChildItem -Path $npmDir -Recurse -Force -ErrorAction SilentlyContinue |\n            Where-Object { $_.Name -in $suspicious -or $_.Extension -eq \".zip\" }\n    }\n\n    if ($found.Count -gt 0) {\n        Write-Fail \"CREDENTIAL DUMPS FOUND \u2014 $($found.Count) file(s)\"\n        $found | ForEach-Object { Write-Detail \"$($_.FullName) ($($_.Length) bytes, $($_.LastWriteTime))\" }\n        Write-Detail \"DO NOT delete \u2014 forensic evidence\"\n        Record \"Credential dumps\" \"\ud83d\udd34\"\n    } else {\n        Write-Pass \"No suspicious files\"\n        Record \"Credential dumps\" \"\u2705\"\n    }\n}\n\nfunction Test-NetworkC2 {\n    Write-Header \"Active C2 network connections\"\n    $hits = netstat -ano 2&amp;gt;$null | Select-String ($C2Ips -join \"|\")\n    if ($hits) {\n        Write-Fail \"ACTIVE CONNECTION TO C2\"\n        $hits | ForEach-Object { Write-Detail $_.Line }\n        Record \"C2 connections\" \"\ud83d\udd34\"\n    } else {\n        Write-Pass \"No active connections to known C2 IPs\"\n        Record \"C2 connections\" \"\u2705\"\n    }\n}\n\nfunction Test-InvisibleFerret {\n    Write-Header \"InvisibleFerret RAT processes\"\n    $pyProcs = Get-CimInstance Win32_Process -Filter \"Name='python.exe' OR Name='python3.exe'\" -ErrorAction SilentlyContinue |\n        Where-Object { $_.CommandLine -match \"__DAEMONIZED|cat\\.py\" }\n\n    if ($pyProcs) {\n        Write-Fail \"INVISIBLEFERRET PROCESS DETECTED\"\n        $pyProcs | ForEach-Object { Write-Detail \"PID $($_.ProcessId): $($_.CommandLine)\" }\n        Record \"InvisibleFerret\" \"\ud83d\udd34\"\n    } else {\n        Write-Pass \"No InvisibleFerret processes found\"\n        Record \"InvisibleFerret\" \"\u2705\"\n    }\n}\n\nfunction Test-MalwareSignatures {\n    Write-Header \"Known malware signatures in source files\"\n    if ($ResolvedDirs.Count -eq 0) { Write-Pass \"No directories to scan\"; Record \"Malware signatures\" \"\u23ed\ufe0f\"; return }\n\n    $pattern = 'rmcej%otb%|Cot%3t=shtP|_\\$_b229|_\\$_1e42|global\\[.!\\.\\]'\n    $hits = Get-SourceFiles -Pattern $pattern -Include @(\"*.js\", \"*.mjs\", \"*.cjs\", \"*.ts\")\n\n    if ($hits.Count -gt 0) {\n        Write-Fail \"MALWARE SIGNATURES in $($hits.Count) file(s)\"\n        $hits | Select-Object -First 20 | ForEach-Object { Write-Detail $_ }\n        Record \"Malware signatures\" \"\ud83d\udd34\"\n    } else {\n        Write-Pass \"No known signatures found\"\n        Record \"Malware signatures\" \"\u2705\"\n    }\n}\n\nfunction Test-LongConfigLines {\n    Write-Header \"Suspiciously long config lines (&amp;gt;200 chars)\"\n    if ($ResolvedDirs.Count -eq 0) { Write-Pass \"No directories to scan\"; Record \"Long config lines\" \"\u23ed\ufe0f\"; return }\n\n    $configNames = @(\n        \"postcss.config.*\", \"next.config.*\", \"tailwind.config.*\", \"eslint.config.*\",\n        \"babel.config.*\", \"jest.config.*\", \"vite.config.*\", \"tsup.config.*\",\n        \"astro.config.*\", \"webpack.config.*\", \"vue.config.*\", \"App.js\"\n    )\n\n    $found = @()\n    foreach ($dir in $ResolvedDirs) {\n        Get-ChildItem -Path $dir -Recurse -File -Include $configNames -ErrorAction SilentlyContinue |\n            Where-Object {\n                $path = $_.FullName\n                -not ($ExcludeDirs | Where-Object { $path -match \"[\\\\/]$_[\\\\/]\" })\n            } | ForEach-Object {\n                $longest = (Get-Content $_.FullName -ErrorAction SilentlyContinue | ForEach-Object { $_.Length } | Measure-Object -Maximum).Maximum\n                if ($longest -gt 200) {\n                    $found += [PSCustomObject]@{ Path = $_.FullName; Length = $longest }\n                }\n            }\n    }\n\n    if ($found.Count -gt 0) {\n        Write-Warn \"FOUND $($found.Count) config file(s) with suspiciously long lines\"\n        $found | ForEach-Object { Write-Detail \"\u26a0\ufe0f  SUSPICIOUS ($($_.Length) chars): $($_.Path)\" }\n        Write-Detail \"Payload hides after ~1300 trailing spaces \u2014 inspect manually\"\n        Record \"Long config lines\" \"\u26a0\ufe0f\"\n    } else {\n        Write-Pass \"All config files have normal line lengths\"\n        Record \"Long config lines\" \"\u2705\"\n    }\n}\n\nfunction Test-FakeFonts {\n    Write-Header \"Fake font payloads (.woff2 with JS)\"\n    if ($ResolvedDirs.Count -eq 0) { Write-Pass \"No directories to scan\"; Record \"Fake fonts\" \"\u23ed\ufe0f\"; return }\n\n    $found = 0\n    foreach ($dir in $ResolvedDirs) {\n        Get-ChildItem -Path $dir -Recurse -File -Filter \"*.woff2\" -ErrorAction SilentlyContinue |\n            Where-Object {\n                $path = $_.FullName\n                -not ($ExcludeDirs | Where-Object { $path -match \"[\\\\/]$_[\\\\/]\" })\n            } | ForEach-Object {\n                $bytes = [System.IO.File]::ReadAllBytes($_.FullName) | Select-Object -First 100\n                $text = [System.Text.Encoding]::ASCII.GetString($bytes)\n                if ($text -match \"global|function|require|module\\.exports\") {\n                    Write-Warn \"JS payload in font: $($_.FullName)\"\n                    $found++\n                }\n            }\n    }\n\n    if ($found -eq 0) {\n        Write-Pass \"No fake font payloads found\"\n        Record \"Fake fonts\" \"\u2705\"\n    } else {\n        Record \"Fake fonts\" \"\u26a0\ufe0f\"\n    }\n}\n\nfunction Test-MaliciousPackages {\n    Write-Header \"Malicious npm packages in package.json\"\n    if ($ResolvedDirs.Count -eq 0) { Write-Pass \"No directories to scan\"; Record \"Malicious packages\" \"\u23ed\ufe0f\"; return }\n\n    $hits = Get-SourceFiles -Pattern $MaliciousPkgsRegex -Include @(\"package.json\")\n\n    if ($hits.Count -gt 0) {\n        Write-Fail \"MALICIOUS PACKAGES in $($hits.Count) file(s)\"\n        $hits | ForEach-Object { Write-Detail $_ }\n        Record \"Malicious packages\" \"\ud83d\udd34\"\n    } else {\n        Write-Pass \"No known malicious packages\"\n        Record \"Malicious packages\" \"\u2705\"\n    }\n}\n\nfunction Test-VsCodeTasks {\n    Write-Header \"VS Code tasks.json with C2 domains\"\n    if ($ResolvedDirs.Count -eq 0) { Write-Pass \"No directories to scan\"; Record \"tasks.json C2\" \"\u23ed\ufe0f\"; return }\n\n    $hits = Get-SourceFiles -Pattern \"$C2VercelRegex|e9b53a7c-2342-4b15-b02d-bd8b8f6a03f9\" -Include @(\"tasks.json\")\n\n    if ($hits.Count -gt 0) {\n        Write-Fail \"MALICIOUS tasks.json FOUND\"\n        $hits | ForEach-Object { Write-Detail $_ }\n        Record \"tasks.json C2\" \"\ud83d\udd34\"\n    } else {\n        Write-Pass \"No malicious tasks.json\"\n        Record \"tasks.json C2\" \"\u2705\"\n    }\n}\n\nfunction Test-SolanaC2 {\n    Write-Header \"Solana/blockchain C2 patterns in source\"\n    if ($ResolvedDirs.Count -eq 0) { Write-Pass \"No directories to scan\"; Record \"Blockchain C2\" \"\u23ed\ufe0f\"; return }\n\n    $hits = Get-SourceFiles -Pattern \"@solana/web3|trongrid|wallet.*memo\" -Include @(\"*.js\", \"*.mjs\", \"*.cjs\", \"*.ts\")\n\n    if ($hits.Count -gt 0) {\n        Write-Warn \"BLOCKCHAIN REFERENCES in $($hits.Count) file(s) \u2014 verify if legitimate\"\n        $hits | Select-Object -First 10 | ForEach-Object { Write-Detail $_ }\n        Record \"Blockchain C2\" \"\u26a0\ufe0f\"\n    } else {\n        Write-Pass \"No blockchain C2 patterns\"\n        Record \"Blockchain C2\" \"\u2705\"\n    }\n}\n\nfunction Test-AxiosCompromised {\n    Write-Header \"Compromised axios versions\"\n    if ($ResolvedDirs.Count -eq 0) { Write-Pass \"No directories to scan\"; Record \"Axios versions\" \"\u23ed\ufe0f\"; return }\n\n    $hits = Get-SourceFiles -Pattern '\"axios\":\\s*\"(1\\.14\\.1|0\\.30\\.4)\"|axios@(1\\.14\\.1|0\\.30\\.4)' `\n        -Include @(\"package.json\", \"pnpm-lock.yaml\", \"package-lock.json\", \"yarn.lock\")\n\n    if ($hits.Count -gt 0) {\n        Write-Fail \"COMPROMISED AXIOS VERSION\"\n        $hits | ForEach-Object { Write-Detail $_ }\n        Record \"Axios versions\" \"\ud83d\udd34\"\n    } else {\n        Write-Pass \"No compromised axios versions\"\n        Record \"Axios versions\" \"\u2705\"\n    }\n}\n\nfunction Test-NxConsole {\n    Write-Header \"Nx Console extension (CVE-2026-48027)\"\n    $exts = \"\"\n    try { $exts = &amp;amp; code --list-extensions --show-versions 2&amp;gt;$null } catch {}\n    if (-not $exts) { try { $exts = &amp;amp; cursor --list-extensions --show-versions 2&amp;gt;$null } catch {} }\n\n    if ($exts -match \"nrwl|nx-console\") {\n        $match = ($exts | Select-String \"nrwl|nx-console\" | Select-Object -First 1).Line\n        if ($match -match \"18\\.95\\.0\") {\n            Write-Fail \"COMPROMISED Nx Console v18.95.0 \u2014 update to 18.100.0+\"\n            Record \"Nx Console\" \"\ud83d\udd34\"\n        } else {\n            Write-Pass \"Nx Console installed, version safe: $match\"\n            Record \"Nx Console\" \"\u2705\"\n        }\n    } else {\n        Write-Pass \"Nx Console not installed\"\n        Record \"Nx Console\" \"\u2705\"\n    }\n}\n\nfunction Test-PostinstallScripts {\n    Write-Header \"Suspicious postinstall/preinstall scripts\"\n    if ($ResolvedDirs.Count -eq 0) { Write-Pass \"No directories to scan\"; Record \"postinstall\" \"\u23ed\ufe0f\"; return }\n\n    $safePatterns = @(\"prisma\", \"patch-package\", \"husky\", \"ngcc\", \"electron-rebuild\",\n        \"node-gyp\", \"esbuild\", \"tsc \", \"tsx \", \"npx prisma\", \"playwright\", \"puppeteer\",\n        \"opencollective\", \"is-ci\", \"npm run build\", \"pnpm run build\", \"yarn build\",\n        \"expo-configure\", \"pod-install\")\n\n    $found = 0\n    foreach ($dir in $ResolvedDirs) {\n        Get-ChildItem -Path $dir -Recurse -Depth 4 -File -Filter \"package.json\" -ErrorAction SilentlyContinue |\n            Where-Object { $_.FullName -notmatch \"[\\\\/]node_modules[\\\\/]\" } |\n            ForEach-Object {\n                try {\n                    $pkg = Get-Content $_.FullName -Raw | ConvertFrom-Json\n                    foreach ($key in @(\"postinstall\", \"preinstall\")) {\n                        $script = $pkg.scripts.$key\n                        if ($script) {\n                            $isSafe = $safePatterns | Where-Object { $script -match [regex]::Escape($_) }\n                            if (-not $isSafe) {\n                                Write-Warn \"REVIEW: $($_.FullName)\"\n                                Write-Detail \"${key}: $script\"\n                                $found++\n                            }\n                        }\n                    }\n                } catch {}\n            }\n    }\n\n    if ($found -eq 0) {\n        Write-Pass \"No suspicious install scripts\"\n        Record \"postinstall\" \"\u2705\"\n    } else {\n        Record \"postinstall\" \"\u26a0\ufe0f\"\n    }\n}\n\nfunction Test-PropagationArtifacts {\n    Write-Header \"Propagation artifacts (.bat files)\"\n    if ($ResolvedDirs.Count -eq 0) { Write-Pass \"No directories to scan\"; Record \"Propagation\" \"\u23ed\ufe0f\"; return }\n\n    $found = 0\n    foreach ($dir in $ResolvedDirs) {\n        Get-ChildItem -Path $dir -Recurse -File -ErrorAction SilentlyContinue |\n            Where-Object { $_.Name -in @(\"temp_auto_push.bat\", \"config.bat\") -and $_.FullName -notmatch \"[\\\\/]node_modules[\\\\/]\" } |\n            ForEach-Object {\n                Write-Warn \"Propagation artifact: $($_.FullName)\"\n                $found++\n            }\n    }\n\n    if ($found -eq 0) {\n        Write-Pass \"No propagation artifacts\"\n        Record \"Propagation\" \"\u2705\"\n    } else {\n        Record \"Propagation\" \"\u26a0\ufe0f\"\n    }\n}\n\nfunction Test-MegalodonActions {\n    Write-Header \"Megalodon GitHub Actions injection\"\n    if ($ResolvedDirs.Count -eq 0) { Write-Pass \"No directories to scan\"; Record \"GH Actions\" \"\u23ed\ufe0f\"; return }\n\n    $found = 0\n    foreach ($dir in $ResolvedDirs) {\n        Get-ChildItem -Path $dir -Recurse -File -Include @(\"*.yml\", \"*.yaml\") -ErrorAction SilentlyContinue |\n            Where-Object { $_.FullName -match \"\\.github[\\\\/]workflows\" } |\n            ForEach-Object {\n                $content = Get-Content $_.FullName -Raw -ErrorAction SilentlyContinue\n                if ($content -match 'curl\\s.*\\|\\s*(sh|bash)|wget\\s.*\\|\\s*(sh|bash)|base64\\s+(-d|--decode)\\s*\\||\\beval\\s+\\$\\(') {\n                    Write-Warn \"Suspicious pattern in: $($_.FullName)\"\n                    $found++\n                }\n            }\n    }\n\n    if ($found -eq 0) {\n        Write-Pass \"No suspicious Actions patterns\"\n        Record \"GH Actions\" \"\u2705\"\n    } else {\n        Record \"GH Actions\" \"\u26a0\ufe0f\"\n    }\n}\n\nfunction Test-GitHooks {\n    Write-Header \"Git hooks integrity\"\n    $found = 0\n\n    $hooksPath = git config --global core.hooksPath 2&amp;gt;$null\n    if ($hooksPath) {\n        Write-Warn \"Global hooks path: $hooksPath\"\n        $found++\n    } else {\n        Write-Pass \"No global hooksPath override\"\n    }\n\n    if ($found -eq 0) { Record \"Git hooks\" \"\u2705\" } else { Record \"Git hooks\" \"\u26a0\ufe0f\" }\n}\n\nfunction Test-NpmrcTokens {\n    Write-Header \"npm auth tokens (.npmrc)\"\n    $npmrc = \"$env:USERPROFILE\\.npmrc\"\n    if (Test-Path $npmrc) {\n        $tokenLines = (Get-Content $npmrc | Select-String \"authToken|_auth|_password\").Count\n        if ($tokenLines -gt 0) {\n            Write-Warn \".npmrc contains $tokenLines line(s) with auth tokens\"\n            Write-Detail \"If compromised, rotate these tokens immediately\"\n            Write-Detail \"Token values intentionally hidden \u2014 inspect manually\"\n            Record \".npmrc tokens\" \"\u26a0\ufe0f\"\n        } else {\n            Write-Pass \".npmrc exists but no auth tokens\"\n            Record \".npmrc tokens\" \"\u2705\"\n        }\n    } else {\n        Write-Pass \"No .npmrc file\"\n        Record \".npmrc tokens\" \"\u2705\"\n    }\n}\n\nfunction Test-GlobalPackages {\n    Write-Header \"Global packages\"\n    Write-Detail \"npm global:\"\n    npm ls -g --depth=0 2&amp;gt;$null | Select-Object -Skip 1 | ForEach-Object { Write-Detail \"  $_\" }\n\n    if (Get-Command pnpm -ErrorAction SilentlyContinue) {\n        Write-Detail \"pnpm global:\"\n        pnpm ls -g 2&amp;gt;$null | Select-Object -Skip 1 | ForEach-Object { Write-Detail \"  $_\" }\n    }\n\n    Write-Pass \"Review lists above for unfamiliar packages\"\n    Record \"Global packages\" \"\ud83d\udc40\"\n}\n\nfunction Test-Extensions {\n    Write-Header \"Editor extensions\"\n    $exts = @()\n    try { $exts = &amp;amp; code --list-extensions 2&amp;gt;$null } catch {}\n    if (-not $exts) { try { $exts = &amp;amp; cursor --list-extensions 2&amp;gt;$null } catch {} }\n\n    if ($exts) {\n        $exts | ForEach-Object { Write-Detail $_ }\n        Write-Pass \"Review for unfamiliar extensions\"\n    } else {\n        Write-Pass \"No editor extensions found (or CLI not available)\"\n    }\n    Record \"Extensions\" \"\ud83d\udc40\"\n}\n\nfunction Test-Persistence {\n    Write-Header \"Persistence mechanisms\"\n\n    Write-Detail \"Scheduled tasks (non-Microsoft):\"\n    Get-ScheduledTask -ErrorAction SilentlyContinue |\n        Where-Object { $_.Author -notmatch \"Microsoft|Windows\" -and $_.State -ne \"Disabled\" } |\n        Select-Object -First 20 |\n        ForEach-Object { Write-Detail \"  $($_.TaskName) \u2014 $($_.Author)\" }\n\n    Write-Detail \"Suspicious processes:\"\n    Get-CimInstance Win32_Process -ErrorAction SilentlyContinue |\n        Where-Object { $_.Name -match \"node|npm|npx|python\" -and $_.Name -notmatch \"Code|Electron|cursor\" } |\n        ForEach-Object { Write-Detail \"  PID $($_.ProcessId): $($_.CommandLine)\" }\n\n    Write-Detail \"DNS cache (C2 domains):\"\n    $dnsHits = ipconfig /displaydns 2&amp;gt;$null | Select-String \"$C2DomainsRegex|166\\.88\\.54|260120\\.vercel|default-configuration\\.vercel\"\n    if ($dnsHits) {\n        $dnsHits | ForEach-Object { Write-Warn \"DNS cache hit: $($_.Line.Trim())\" }\n    } else {\n        Write-Detail \"  No C2 domains in DNS cache\"\n    }\n\n    Write-Pass \"Review items above\"\n    Record \"Persistence\" \"\ud83d\udc40\"\n}\n\n# \u2500\u2500\u2500 Deep checks (Windows Event Log) \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 Test-EventLogNetwork {\n    $script:TotalChecks++\n    Write-Header \"Security Event Log \u2014 C2 network events (last 7 days)\"\n    Write-Detail \"This may take a while...\"\n\n    try {\n        $events = Get-WinEvent -FilterHashtable @{\n            LogName = 'Security'; Id = 5156; StartTime = (Get-Date).AddDays(-7)\n        } -MaxEvents 10000 -ErrorAction SilentlyContinue |\n            Where-Object { $_.Message -match \"node|npm|python\" } |\n            Where-Object { $_.Message -match \"166\\.88\\.54|trongrid|aptoslabs|telegram\" }\n\n        if ($events) {\n            Write-Fail \"FOUND $($events.Count) C2 network events\"\n            $events | Select-Object -First 10 | ForEach-Object {\n                Write-Detail \"$($_.TimeCreated): $($_.Message | Select-Object -First 1)\"\n            }\n            Record \"Event Log (network)\" \"\ud83d\udd34\"\n        } else {\n            Write-Pass \"No C2 network events\"\n            Record \"Event Log (network)\" \"\u2705\"\n        }\n    } catch {\n        Write-Detail \"Could not read Security log (requires Admin)\"\n        Record \"Event Log (network)\" \"\u23ed\ufe0f\"\n    }\n}\n\nfunction Test-EventLogProcess {\n    $script:TotalChecks++\n    Write-Header \"Security Event Log \u2014 suspicious process creation (last 7 days)\"\n\n    try {\n        $events = Get-WinEvent -FilterHashtable @{\n            LogName = 'Security'; Id = 4688; StartTime = (Get-Date).AddDays(-7)\n        } -MaxEvents 10000 -ErrorAction SilentlyContinue |\n            Where-Object { $_.Message -match \"taskkill|wmic useraccount|tmp7A863DD1\" }\n\n        if ($events) {\n            Write-Fail \"SUSPICIOUS PROCESS CREATION EVENTS\"\n            $events | Select-Object -First 10 | ForEach-Object {\n                Write-Detail \"$($_.TimeCreated): $($_.Message | Select-Object -First 1)\"\n            }\n            Record \"Event Log (process)\" \"\ud83d\udd34\"\n        } else {\n            Write-Pass \"No suspicious process events\"\n            Record \"Event Log (process)\" \"\u2705\"\n        }\n    } catch {\n        Write-Detail \"Could not read Security log (requires Admin)\"\n        Record \"Event Log (process)\" \"\u23ed\ufe0f\"\n    }\n}\n\n# \u2500\u2500\u2500 Summary \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\nfunction Show-Summary {\n    Write-Host \"\"\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\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\" -ForegroundColor White\n    Write-Host \" SUMMARY\" -ForegroundColor White\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\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\" -ForegroundColor White\n    Write-Host \"\"\n\n    for ($i = 0; $i -lt $script:CheckNames.Count; $i++) {\n        $num = ($i + 1).ToString().PadLeft(3)\n        $name = $script:CheckNames[$i].PadRight(35)\n        Write-Host \" $num  $name $($script:CheckResults[$i])\"\n    }\n\n    Write-Host \"\"\n\n    if ($script:Findings -gt 0) {\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\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\" -ForegroundColor Red\n        Write-Host \" $($script:Findings) FINDING(S) \u2014 review the details above\" -ForegroundColor Red\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\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\" -ForegroundColor Red\n        Write-Host \"\"\n        Write-Host \" \ud83d\udd34 = confirmed compromise indicator. Stop all work, rotate secrets.\"\n        Write-Host \" \u26a0\ufe0f  = suspicious, needs manual verification.\"\n        Write-Host \" \ud83d\udc40 = informational, review for anything unexpected.\"\n        Write-Host \"\"\n        Write-Host \" If you see \ud83d\udd34 findings:\" -ForegroundColor Red\n        Write-Host \"   1. DO NOT push to any repository\"\n        Write-Host \"   2. DO NOT delete evidence files\"\n        Write-Host \"   3. Report to your security lead with this output\"\n        Write-Host \"   4. Rotate ALL secrets (npm tokens, SSH keys, API keys, .env values)\"\n    } else {\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\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\" -ForegroundColor Green\n        Write-Host \" ALL CLEAR \u2014 no compromise indicators found\" -ForegroundColor Green\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\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\" -ForegroundColor Green\n        Write-Host \"\"\n        Write-Host \" \ud83d\udc40 items are informational \u2014 review briefly.\"\n        Write-Host \" Clean scan does not guarantee absence of novel threats.\"\n    }\n\n    Write-Host \"\"\n}\n\n# \u2500\u2500\u2500 Main \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\u2500\n\nWrite-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\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\"\nWrite-Host \" Supply Chain Malware Scanner v$Version\"\nWrite-Host \" PolinRider / InvisibleFerret / Megalodon\"\nWrite-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\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\"\nWrite-Host \"\"\nWrite-Host \" Platform:   Windows $([System.Environment]::OSVersion.Version)\"\nWrite-Host \" User:       $env:USERNAME\"\nWrite-Host \" Date:       $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss UTC' -AsUTC)\"\nWrite-Host \" Scan dirs:  $($ResolvedDirs -join ', ')\"\nWrite-Host \" Deep scan:  $Deep\"\n\n# Core IOCs\nTest-LockFile\nTest-CredentialDumps\nTest-NetworkC2\nTest-InvisibleFerret\n\n# Source code infection\nTest-MalwareSignatures\nTest-LongConfigLines\nTest-FakeFonts\nTest-MaliciousPackages\nTest-VsCodeTasks\nTest-SolanaC2\n\n# Supply chain\nTest-AxiosCompromised\nTest-NxConsole\nTest-PostinstallScripts\n\n# Propagation\nTest-PropagationArtifacts\nTest-MegalodonActions\n\n# Environment integrity\nTest-GitHooks\nTest-NpmrcTokens\nTest-GlobalPackages\nTest-Extensions\nTest-Persistence\n\n# Deep checks\nif ($Deep) {\n    Test-EventLogNetwork\n    Test-EventLogProcess\n}\n\nShow-Summary\n\nif ($script:Findings -gt 0) { exit 1 } else { exit 0 }\n\n\n#!/usr/bin/env bash\n# scan-supply-chain.sh \u2014 Supply Chain Malware Scanner\n# Threats: PolinRider, InvisibleFerret, Megalodon, compromised npm packages\n# Read-only: does NOT modify any files or system state\n# Safe: never prints credential or token values\n#\n# Usage: ./scan-supply-chain.sh [--deep] [--scan-dirs \"/path/a /path/b\"]\n# --deep    Enable slow macOS log checks (DNS, system log C2 queries)\n# --scan-dirs  Override default source code directories to scan\n\nset -euo pipefail\n\nVERSION=\"1.0.0\"\n\n# \u2500\u2500\u2500 Configuration \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\nDEFAULT_SCAN_DIRS=\"$HOME/git $HOME/projects $HOME/dev $HOME/code $HOME/repos\"\nSCAN_DIRS=\"${SCAN_DIRS:-$DEFAULT_SCAN_DIRS}\"\nMAX_DEPTH=6\nDEEP_SCAN=false\n\nEXCLUDE_DIRS=\"node_modules .next dist .git build .turbo .expo .cache\"\n\n# Known C2 indicators\nC2_IPS=\"166.88.54.158\"\nC2_DOMAINS=\"trongrid|aptoslabs|bsc-dataseed|bsc-rpc\\.publicnode|api\\.telegram\\.org\"\nC2_VERCEL=\"default-configuration\\.vercel|vscode-settings-bootstrap\\.vercel|vscode-load-config\\.vercel|260120\\.vercel\"\n\n# Malicious npm packages (PolinRider distribution vector)\nMALICIOUS_PKGS=\"tailwindcss-style-animate|tailwind-mainanimation|tailwind-tionbased|tailwindcss-typography-style|tailwindcss-style-modify|tailwindcss-animate-style\"\n\n# Known safe postinstall commands (prefix match)\nSAFE_POSTINSTALL=\"prisma generate|patch-package|husky|ngcc|electron-rebuild|node-gyp|esbuild|tsc |tsx |ts-node|npx prisma|playwright install|puppeteer install|opencollective|is-ci|npm run build|pnpm run build|yarn build|expo-configure-project|pod-install\"\n\n# \u2500\u2500\u2500 Output 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\n\nif [[ -t 1 ]]; then\n  RED='\\033[0;31m'; GREEN='\\033[0;32m'; YELLOW='\\033[1;33m'\n  CYAN='\\033[0;36m'; BOLD='\\033[1m'; DIM='\\033[2m'; NC='\\033[0m'\nelse\n  RED=''; GREEN=''; YELLOW=''; CYAN=''; BOLD=''; DIM=''; NC=''\nfi\n\nTOTAL_CHECKS=20\nCURRENT=0\ndeclare -a CHECK_NAMES=()\ndeclare -a CHECK_RESULTS=()\ndeclare -a CHECK_DETAILS=()\nFINDINGS=0\n\nheader() {\n  CURRENT=$((CURRENT + 1))\n  printf \"\\n${CYAN}[%2d/%d]${NC} ${BOLD}%s${NC}\\n\" \"$CURRENT\" \"$TOTAL_CHECKS\" \"$1\"\n}\n\npass()   { printf \"       ${GREEN}\u2705 %s${NC}\\n\" \"$1\"; }\nwarn()   { printf \"       ${YELLOW}\u26a0\ufe0f  %s${NC}\\n\" \"$1\"; FINDINGS=$((FINDINGS + 1)); }\nfail()   { printf \"       ${RED}\ud83d\udd34 %s${NC}\\n\" \"$1\"; FINDINGS=$((FINDINGS + 1)); }\ndetail() { printf \"       ${DIM}   %s${NC}\\n\" \"$1\"; }\n\nrecord() {\n  CHECK_NAMES+=(\"$1\")\n  CHECK_RESULTS+=(\"$2\")\n}\n\n# \u2500\u2500\u2500 Resolve scan directories \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\nRESOLVED_DIRS=()\n\nresolve_dirs() {\n  for dir in $SCAN_DIRS; do\n    if [[ -d \"$dir\" ]]; then\n      RESOLVED_DIRS+=(\"$dir\")\n    fi\n  done\n  if [[ ${#RESOLVED_DIRS[@]} -eq 0 ]]; then\n    printf \"${YELLOW}Warning: no scan directories found. Checked: %s${NC}\\n\" \"$SCAN_DIRS\"\n    printf \"Override with: SCAN_DIRS=\\\"/your/code\\\" ./scan-supply-chain.sh\\n\"\n  fi\n}\n\n# Build find exclude arguments: -path '*/node_modules' -prune -o ...\nbuild_find_excludes() {\n  local excludes=\"\"\n  for d in $EXCLUDE_DIRS; do\n    excludes=\"$excludes -path '*/$d' -prune -o\"\n  done\n  echo \"$excludes\"\n}\n\n# Build grep exclude-dir arguments\nbuild_grep_excludes() {\n  local excludes=\"\"\n  for d in $EXCLUDE_DIRS; do\n    excludes=\"$excludes --exclude-dir=$d\"\n  done\n  echo \"$excludes\"\n}\n\nGREP_EXCLUDES=$(build_grep_excludes)\n\n# \u2500\u2500\u2500 Check functions \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# 1. Lock file \u2014 direct evidence of payload execution\ncheck_lock_file() {\n  header \"Lock file (payload execution marker)\"\n  local lockfile=\"/tmp/tmp7A863DD1.tmp\"\n  if [[ -f \"$lockfile\" ]]; then\n    fail \"LOCK FILE EXISTS at $lockfile \u2014 payload executed on this machine\"\n    detail \"$(ls -la \"$lockfile\")\"\n    record \"Lock file\" \"\ud83d\udd34\"\n  else\n    pass \"Not found\"\n    record \"Lock file\" \"\u2705\"\n  fi\n}\n\n# 2. Credential dumps in ~/.npm staging directory\ncheck_credential_dumps() {\n  header \"Credential dumps (~/.npm staging)\"\n  local found=0\n  local files\n  files=$(find \"$HOME/.npm\" \\( \\\n    -name \"_credentials.json\" -o \\\n    -name \"_sysenv.json\" -o \\\n    -name \"_sysenv.env\" -o \\\n    -name \"_info.json\" -o \\\n    -name \"*.zip\" \\\n  \\) 2&amp;gt;/dev/null || true)\n\n  if [[ -n \"$files\" ]]; then\n    found=$(echo \"$files\" | wc -l | tr -d ' ')\n    fail \"CREDENTIAL DUMPS FOUND \u2014 $found file(s) in ~/.npm\"\n    echo \"$files\" | while IFS= read -r f; do\n      detail \"$(ls -la \"$f\" 2&amp;gt;/dev/null)\"\n    done\n    detail \"DO NOT delete these \u2014 they are forensic evidence\"\n    record \"Credential dumps\" \"\ud83d\udd34\"\n  else\n    pass \"No suspicious files\"\n    record \"Credential dumps\" \"\u2705\"\n  fi\n}\n\n# 3. Active network connections to known C2\ncheck_network_c2() {\n  header \"Active C2 network connections\"\n  local hits\n  hits=$(netstat -an 2&amp;gt;/dev/null | grep -iE \"$C2_IPS\" || true)\n  if [[ -n \"$hits\" ]]; then\n    fail \"ACTIVE CONNECTION TO C2 SERVER\"\n    echo \"$hits\" | while IFS= read -r line; do detail \"$line\"; done\n    record \"C2 connections\" \"\ud83d\udd34\"\n  else\n    pass \"No active connections to known C2 IPs\"\n    record \"C2 connections\" \"\u2705\"\n  fi\n}\n\n# 4. InvisibleFerret active processes\ncheck_invisibleferret() {\n  header \"InvisibleFerret RAT processes\"\n  local hits\n  hits=$(ps aux 2&amp;gt;/dev/null | grep -iE \"__DAEMONIZED|cat\\.py\" | grep -v grep || true)\n  if [[ -n \"$hits\" ]]; then\n    fail \"INVISIBLEFERRET PROCESS DETECTED\"\n    echo \"$hits\" | while IFS= read -r line; do detail \"$line\"; done\n    record \"InvisibleFerret\" \"\ud83d\udd34\"\n  else\n    pass \"No InvisibleFerret processes found\"\n    record \"InvisibleFerret\" \"\u2705\"\n  fi\n}\n\n# 5. Known malware signatures in JS files\ncheck_malware_signatures() {\n  header \"Known malware signatures in source files\"\n  [[ ${#RESOLVED_DIRS[@]} -eq 0 ]] &amp;amp;&amp;amp; { pass \"No directories to scan\"; record \"Malware signatures\" \"\u23ed\ufe0f\"; return; }\n\n  local hits\n  hits=$(grep -rl $GREP_EXCLUDES \\\n    --include='*.js' --include='*.mjs' --include='*.cjs' --include='*.ts' \\\n    -E \"rmcej%otb%|Cot%3t=shtP|_\\\\\\$_b229|_\\\\\\$_1e42|global\\['\\!'\\]\" \\\n    \"${RESOLVED_DIRS[@]}\" 2&amp;gt;/dev/null || true)\n\n  if [[ -n \"$hits\" ]]; then\n    local count\n    count=$(echo \"$hits\" | wc -l | tr -d ' ')\n    fail \"MALWARE SIGNATURES FOUND in $count file(s)\"\n    echo \"$hits\" | head -20 | while IFS= read -r f; do detail \"$f\"; done\n    [[ $count -gt 20 ]] &amp;amp;&amp;amp; detail \"... and $((count - 20)) more\"\n    record \"Malware signatures\" \"\ud83d\udd34\"\n  else\n    pass \"No known signatures found\"\n    record \"Malware signatures\" \"\u2705\"\n  fi\n}\n\n# 6. Suspiciously long lines in config files (payload hides after ~1300 spaces)\ncheck_long_config_lines() {\n  header \"Suspiciously long config lines (&amp;gt;200 chars)\"\n  [[ ${#RESOLVED_DIRS[@]} -eq 0 ]] &amp;amp;&amp;amp; { pass \"No directories to scan\"; record \"Long config lines\" \"\u23ed\ufe0f\"; return; }\n\n  local config_names=\"-name 'postcss.config.*' -o -name 'next.config.*' -o -name 'tailwind.config.*' \\\n    -o -name 'eslint.config.*' -o -name 'babel.config.*' -o -name 'jest.config.*' \\\n    -o -name 'vite.config.*' -o -name 'tsup.config.*' -o -name 'astro.config.*' \\\n    -o -name 'webpack.config.*' -o -name 'vue.config.*' -o -name 'App.js'\"\n\n  local found=0\n  local output=\"\"\n\n  for dir in \"${RESOLVED_DIRS[@]}\"; do\n    while IFS= read -r file; do\n      [[ -z \"$file\" ]] &amp;amp;&amp;amp; continue\n      local longest\n      longest=$(awk '{ print length }' \"$file\" 2&amp;gt;/dev/null | sort -rn | head -1)\n      if [[ -n \"$longest\" ]] &amp;amp;&amp;amp; [[ \"$longest\" -gt 200 ]] 2&amp;gt;/dev/null; then\n        output+=\"\u26a0\ufe0f  SUSPICIOUS ($longest chars): $file\"$'\\n'\n        found=$((found + 1))\n      fi\n    done &amp;lt; &amp;lt;(find \"$dir\" -maxdepth \"$MAX_DEPTH\" \\\n      -path '*/node_modules' -prune -o \\\n      -path '*/.next' -prune -o \\\n      -path '*/dist' -prune -o \\\n      -path '*/.git' -prune -o \\\n      \\( -name 'postcss.config.*' -o -name 'next.config.*' -o -name 'tailwind.config.*' \\\n         -o -name 'eslint.config.*' -o -name 'babel.config.*' -o -name 'jest.config.*' \\\n         -o -name 'vite.config.*' -o -name 'tsup.config.*' -o -name 'astro.config.*' \\\n         -o -name 'webpack.config.*' -o -name 'vue.config.*' -o -name 'App.js' \\) \\\n      -print 2&amp;gt;/dev/null)\n  done\n\n  if [[ $found -gt 0 ]]; then\n    warn \"FOUND $found config file(s) with suspiciously long lines\"\n    echo \"$output\" | while IFS= read -r line; do [[ -n \"$line\" ]] &amp;amp;&amp;amp; detail \"$line\"; done\n    detail \"Inspect these files \u2014 the payload hides after ~1300 trailing spaces\"\n    record \"Long config lines\" \"\u26a0\ufe0f\"\n  else\n    pass \"All config files have normal line lengths\"\n    record \"Long config lines\" \"\u2705\"\n  fi\n}\n\n# 7. Fake font files (.woff2 containing JS)\ncheck_fake_fonts() {\n  header \"Fake font payloads (.woff2 with JS)\"\n  [[ ${#RESOLVED_DIRS[@]} -eq 0 ]] &amp;amp;&amp;amp; { pass \"No directories to scan\"; record \"Fake fonts\" \"\u23ed\ufe0f\"; return; }\n\n  local found=0\n  for dir in \"${RESOLVED_DIRS[@]}\"; do\n    while IFS= read -r file; do\n      [[ -z \"$file\" ]] &amp;amp;&amp;amp; continue\n      if head -c 100 \"$file\" 2&amp;gt;/dev/null | grep -qE \"global|function|require|module\\.exports\"; then\n        warn \"JS payload in font: $file\"\n        found=$((found + 1))\n      fi\n    done &amp;lt; &amp;lt;(find \"$dir\" -maxdepth \"$MAX_DEPTH\" \\\n      -path '*/node_modules' -prune -o \\\n      -path '*/.next' -prune -o \\\n      -name '*.woff2' -print 2&amp;gt;/dev/null)\n  done\n\n  if [[ $found -gt 0 ]]; then\n    record \"Fake fonts\" \"\u26a0\ufe0f\"\n  else\n    pass \"No fake font payloads found\"\n    record \"Fake fonts\" \"\u2705\"\n  fi\n}\n\n# 8. Malicious npm packages in package.json\ncheck_malicious_packages() {\n  header \"Malicious npm packages in package.json\"\n  [[ ${#RESOLVED_DIRS[@]} -eq 0 ]] &amp;amp;&amp;amp; { pass \"No directories to scan\"; record \"Malicious packages\" \"\u23ed\ufe0f\"; return; }\n\n  local hits\n  hits=$(grep -rl $GREP_EXCLUDES \\\n    --include='package.json' \\\n    -E \"$MALICIOUS_PKGS\" \\\n    \"${RESOLVED_DIRS[@]}\" 2&amp;gt;/dev/null || true)\n\n  if [[ -n \"$hits\" ]]; then\n    local count\n    count=$(echo \"$hits\" | wc -l | tr -d ' ')\n    fail \"MALICIOUS PACKAGES in $count package.json file(s)\"\n    echo \"$hits\" | while IFS= read -r f; do detail \"$f\"; done\n    record \"Malicious packages\" \"\ud83d\udd34\"\n  else\n    pass \"No known malicious packages found\"\n    record \"Malicious packages\" \"\u2705\"\n  fi\n}\n\n# 9. VS Code tasks.json with C2 domains\ncheck_vscode_tasks() {\n  header \"VS Code tasks.json with C2 domains\"\n  [[ ${#RESOLVED_DIRS[@]} -eq 0 ]] &amp;amp;&amp;amp; { pass \"No directories to scan\"; record \"tasks.json C2\" \"\u23ed\ufe0f\"; return; }\n\n  local hits\n  hits=$(grep -rl $GREP_EXCLUDES \\\n    --include='tasks.json' \\\n    -E \"$C2_VERCEL|e9b53a7c-2342-4b15-b02d-bd8b8f6a03f9\" \\\n    \"${RESOLVED_DIRS[@]}\" 2&amp;gt;/dev/null || true)\n\n  if [[ -n \"$hits\" ]]; then\n    fail \"MALICIOUS tasks.json FOUND\"\n    echo \"$hits\" | while IFS= read -r f; do detail \"$f\"; done\n    record \"tasks.json C2\" \"\ud83d\udd34\"\n  else\n    pass \"No malicious tasks.json files found\"\n    record \"tasks.json C2\" \"\u2705\"\n  fi\n}\n\n# 10. Solana/blockchain C2 patterns in source code\ncheck_solana_c2() {\n  header \"Solana/blockchain C2 patterns in source\"\n  [[ ${#RESOLVED_DIRS[@]} -eq 0 ]] &amp;amp;&amp;amp; { pass \"No directories to scan\"; record \"Blockchain C2\" \"\u23ed\ufe0f\"; return; }\n\n  local hits\n  hits=$(grep -rl $GREP_EXCLUDES \\\n    --include='*.js' --include='*.mjs' --include='*.cjs' --include='*.ts' \\\n    -E \"@solana/web3|trongrid|wallet.*memo\" \\\n    \"${RESOLVED_DIRS[@]}\" 2&amp;gt;/dev/null || true)\n\n  if [[ -n \"$hits\" ]]; then\n    local count\n    count=$(echo \"$hits\" | wc -l | tr -d ' ')\n    warn \"BLOCKCHAIN REFERENCES in $count file(s) \u2014 verify if legitimate\"\n    echo \"$hits\" | head -10 | while IFS= read -r f; do detail \"$f\"; done\n    detail \"May be legitimate if this project uses Solana/Tron \u2014 verify manually\"\n    record \"Blockchain C2\" \"\u26a0\ufe0f\"\n  else\n    pass \"No blockchain C2 patterns found\"\n    record \"Blockchain C2\" \"\u2705\"\n  fi\n}\n\n# 11. Compromised axios versions (1.14.1, 0.30.4)\ncheck_axios_compromised() {\n  header \"Compromised axios versions\"\n  [[ ${#RESOLVED_DIRS[@]} -eq 0 ]] &amp;amp;&amp;amp; { pass \"No directories to scan\"; record \"Axios versions\" \"\u23ed\ufe0f\"; return; }\n\n  local hits\n  hits=$(grep -rl $GREP_EXCLUDES \\\n    --include='package.json' --include='pnpm-lock.yaml' \\\n    --include='package-lock.json' --include='yarn.lock' \\\n    -E '\"axios\":\\s*\"(1\\.14\\.1|0\\.30\\.4)\"|axios@(1\\.14\\.1|0\\.30\\.4)' \\\n    \"${RESOLVED_DIRS[@]}\" 2&amp;gt;/dev/null || true)\n\n  if [[ -n \"$hits\" ]]; then\n    fail \"COMPROMISED AXIOS VERSION found\"\n    echo \"$hits\" | while IFS= read -r f; do detail \"$f\"; done\n    detail \"axios 1.14.1 and 0.30.4 were published by a compromised maintainer\"\n    record \"Axios versions\" \"\ud83d\udd34\"\n  else\n    pass \"No compromised axios versions found\"\n    record \"Axios versions\" \"\u2705\"\n  fi\n}\n\n# 12. Nx Console CVE-2026-48027\ncheck_nx_console() {\n  header \"Nx Console extension (CVE-2026-48027)\"\n  local exts=\"\"\n  exts=$(code --list-extensions --show-versions 2&amp;gt;/dev/null || \\\n         cursor --list-extensions --show-versions 2&amp;gt;/dev/null || true)\n\n  if echo \"$exts\" | grep -iqE \"nrwl\\.angular-console|nx-console\"; then\n    local version\n    version=$(echo \"$exts\" | grep -iE \"nrwl|nx-console\" | head -1)\n    if echo \"$version\" | grep -q \"18\\.95\\.0\"; then\n      fail \"COMPROMISED Nx Console v18.95.0 installed \u2014 update to 18.100.0+\"\n      detail \"$version\"\n      record \"Nx Console\" \"\ud83d\udd34\"\n    else\n      pass \"Nx Console installed but version is safe: $version\"\n      record \"Nx Console\" \"\u2705\"\n    fi\n  else\n    pass \"Nx Console not installed\"\n    record \"Nx Console\" \"\u2705\"\n  fi\n}\n\n# 13. Suspicious postinstall/preinstall scripts\ncheck_postinstall_scripts() {\n  header \"Suspicious postinstall/preinstall scripts\"\n  [[ ${#RESOLVED_DIRS[@]} -eq 0 ]] &amp;amp;&amp;amp; { pass \"No directories to scan\"; record \"postinstall\" \"\u23ed\ufe0f\"; return; }\n\n  local found=0\n  for dir in \"${RESOLVED_DIRS[@]}\"; do\n    while IFS= read -r pkg; do\n      [[ -z \"$pkg\" ]] &amp;amp;&amp;amp; continue\n      local scripts\n      scripts=$(python3 -c \"\nimport json, sys\ntry:\n    d = json.load(open('$pkg'))\n    s = d.get('scripts', {})\n    for k in ('postinstall', 'preinstall'):\n        if k in s:\n            print(f'{k}: {s[k]}')\nexcept: pass\n\" 2&amp;gt;/dev/null || true)\n\n      if [[ -n \"$scripts\" ]]; then\n        while IFS= read -r script_line; do\n          local cmd=\"${script_line#*: }\"\n          local is_safe=false\n          IFS='|' read -ra safe_patterns &amp;lt;&amp;lt;&amp;lt; \"$SAFE_POSTINSTALL\"\n          for pattern in \"${safe_patterns[@]}\"; do\n            if [[ \"$cmd\" == *\"$pattern\"* ]]; then\n              is_safe=true\n              break\n            fi\n          done\n          if ! $is_safe; then\n            warn \"REVIEW: $pkg\"\n            detail \"$script_line\"\n            found=$((found + 1))\n          fi\n        done &amp;lt;&amp;lt;&amp;lt; \"$scripts\"\n      fi\n    done &amp;lt; &amp;lt;(find \"$dir\" -maxdepth 4 \\\n      -path '*/node_modules' -prune -o \\\n      -name 'package.json' -print 2&amp;gt;/dev/null)\n  done\n\n  if [[ $found -gt 0 ]]; then\n    detail \"Review these scripts \u2014 not all are malicious, but verify unknown commands\"\n    record \"postinstall\" \"\u26a0\ufe0f\"\n  else\n    pass \"No suspicious install scripts found\"\n    record \"postinstall\" \"\u2705\"\n  fi\n}\n\n# 14. Propagation artifacts (.bat files)\ncheck_propagation_artifacts() {\n  header \"Propagation artifacts (.bat files, .gitignore entries)\"\n  [[ ${#RESOLVED_DIRS[@]} -eq 0 ]] &amp;amp;&amp;amp; { pass \"No directories to scan\"; record \"Propagation\" \"\u23ed\ufe0f\"; return; }\n\n  local found=0\n\n  for dir in \"${RESOLVED_DIRS[@]}\"; do\n    local bats\n    bats=$(find \"$dir\" -maxdepth \"$MAX_DEPTH\" \\\n      -path '*/node_modules' -prune -o \\\n      \\( -name 'temp_auto_push.bat' -o -name 'config.bat' \\) \\\n      -print 2&amp;gt;/dev/null || true)\n    if [[ -n \"$bats\" ]]; then\n      echo \"$bats\" | while IFS= read -r f; do\n        warn \"Propagation artifact: $f\"\n        found=$((found + 1))\n      done\n    fi\n  done\n\n  local gitignore_refs\n  gitignore_refs=$(grep -rl $GREP_EXCLUDES \\\n    --include='.gitignore' \\\n    'config\\.bat' \\\n    \"${RESOLVED_DIRS[@]}\" 2&amp;gt;/dev/null || true)\n  if [[ -n \"$gitignore_refs\" ]]; then\n    echo \"$gitignore_refs\" | while IFS= read -r f; do\n      warn \"config.bat in .gitignore: $f\"\n      found=$((found + 1))\n    done\n  fi\n\n  if [[ $found -eq 0 ]]; then\n    pass \"No propagation artifacts found\"\n    record \"Propagation\" \"\u2705\"\n  else\n    record \"Propagation\" \"\u26a0\ufe0f\"\n  fi\n}\n\n# 15. Megalodon GitHub Actions injection\ncheck_megalodon_actions() {\n  header \"Megalodon GitHub Actions injection\"\n  [[ ${#RESOLVED_DIRS[@]} -eq 0 ]] &amp;amp;&amp;amp; { pass \"No directories to scan\"; record \"GH Actions\" \"\u23ed\ufe0f\"; return; }\n\n  local found=0\n  for dir in \"${RESOLVED_DIRS[@]}\"; do\n    while IFS= read -r workflow; do\n      [[ -z \"$workflow\" ]] &amp;amp;&amp;amp; continue\n      if grep -qE 'curl\\s.*\\|\\s*(sh|bash)|wget\\s.*\\|\\s*(sh|bash)|base64\\s+(-d|--decode)\\s*\\||\\beval\\s+\\$\\(' \"$workflow\" 2&amp;gt;/dev/null; then\n        warn \"Suspicious pattern in: $workflow\"\n        found=$((found + 1))\n      fi\n    done &amp;lt; &amp;lt;(find \"$dir\" -maxdepth \"$MAX_DEPTH\" \\\n      -path '*/.github/workflows' -type d -exec find {} -name '*.yml' -o -name '*.yaml' \\; 2&amp;gt;/dev/null)\n  done\n\n  if [[ $found -gt 0 ]]; then\n    detail \"Review these workflows \u2014 curl|bash and base64 decode in Actions are red flags\"\n    record \"GH Actions\" \"\u26a0\ufe0f\"\n  else\n    pass \"No suspicious GitHub Actions patterns found\"\n    record \"GH Actions\" \"\u2705\"\n  fi\n}\n\n# 16. Git hooks \u2014 hijacked global hooks\ncheck_git_hooks() {\n  header \"Git hooks integrity\"\n  local found=0\n\n  local hooks_path\n  hooks_path=$(git config --global core.hooksPath 2&amp;gt;/dev/null || true)\n  if [[ -n \"$hooks_path\" ]]; then\n    warn \"Global hooks path is set: $hooks_path\"\n    if [[ -d \"$hooks_path\" ]]; then\n      detail \"Contents: $(ls \"$hooks_path\" 2&amp;gt;/dev/null || echo '(empty)')\"\n    fi\n    found=$((found + 1))\n  else\n    pass \"No global hooksPath override\"\n  fi\n\n  for hook_dir in \"$HOME/.config/git/hooks\" \"$HOME/.git-templates/hooks\"; do\n    if [[ -d \"$hook_dir\" ]] &amp;amp;&amp;amp; [[ -n \"$(ls -A \"$hook_dir\" 2&amp;gt;/dev/null)\" ]]; then\n      warn \"Hook templates found in: $hook_dir\"\n      detail \"$(ls \"$hook_dir\")\"\n      found=$((found + 1))\n    fi\n  done\n\n  if [[ $found -eq 0 ]]; then\n    record \"Git hooks\" \"\u2705\"\n  else\n    detail \"Verify these hooks are legitimate \u2014 malware uses global hooks for persistence\"\n    record \"Git hooks\" \"\u26a0\ufe0f\"\n  fi\n}\n\n# 17. npm auth tokens (.npmrc) \u2014 existence check only, NEVER print values\ncheck_npmrc_tokens() {\n  header \"npm auth tokens (.npmrc)\"\n  local npmrc=\"$HOME/.npmrc\"\n  if [[ -f \"$npmrc\" ]]; then\n    local token_lines\n    token_lines=$(grep -cE '(authToken|_auth|_password)' \"$npmrc\" 2&amp;gt;/dev/null || echo \"0\")\n    if [[ \"$token_lines\" -gt 0 ]]; then\n      warn \".npmrc contains $token_lines line(s) with auth tokens\"\n      detail \"If compromised, rotate these tokens immediately\"\n      detail \"Token values intentionally hidden \u2014 inspect manually: cat ~/.npmrc\"\n      record \".npmrc tokens\" \"\u26a0\ufe0f\"\n    else\n      pass \".npmrc exists but contains no auth tokens\"\n      record \".npmrc tokens\" \"\u2705\"\n    fi\n  else\n    pass \"No .npmrc file found\"\n    record \".npmrc tokens\" \"\u2705\"\n  fi\n}\n\n# 18. Global packages inventory\ncheck_global_packages() {\n  header \"Global packages (npm/pnpm)\"\n  printf \"       ${DIM}npm global:${NC}\\n\"\n  npm ls -g --depth=0 2&amp;gt;/dev/null | tail -n +2 | while IFS= read -r line; do detail \"$line\"; done\n\n  if command -v pnpm &amp;amp;&amp;gt;/dev/null; then\n    printf \"       ${DIM}pnpm global:${NC}\\n\"\n    pnpm ls -g 2&amp;gt;/dev/null | tail -n +2 | while IFS= read -r line; do detail \"$line\"; done\n  fi\n\n  pass \"Review the lists above for any unfamiliar packages\"\n  record \"Global packages\" \"\ud83d\udc40\"\n}\n\n# 19. VS Code / Cursor extensions\ncheck_extensions() {\n  header \"Editor extensions\"\n  local exts=\"\"\n  if command -v code &amp;amp;&amp;gt;/dev/null; then\n    printf \"       ${DIM}VS Code extensions:${NC}\\n\"\n    exts=$(code --list-extensions 2&amp;gt;/dev/null || true)\n  elif command -v cursor &amp;amp;&amp;gt;/dev/null; then\n    printf \"       ${DIM}Cursor extensions:${NC}\\n\"\n    exts=$(cursor --list-extensions 2&amp;gt;/dev/null || true)\n  fi\n\n  if [[ -n \"$exts\" ]]; then\n    echo \"$exts\" | while IFS= read -r ext; do detail \"$ext\"; done\n    pass \"Review for unfamiliar extensions\"\n  else\n    pass \"No editor extensions found (or editor CLI not available)\"\n  fi\n  record \"Extensions\" \"\ud83d\udc40\"\n}\n\n# 20. Persistence mechanisms\ncheck_persistence() {\n  header \"Persistence mechanisms\"\n  local found=0\n\n  if [[ \"$(uname)\" == \"Darwin\" ]]; then\n    local agents_dir=\"$HOME/Library/LaunchAgents\"\n    if [[ -d \"$agents_dir\" ]] &amp;amp;&amp;amp; [[ -n \"$(ls -A \"$agents_dir\" 2&amp;gt;/dev/null)\" ]]; then\n      printf \"       ${DIM}LaunchAgents:${NC}\\n\"\n      ls \"$agents_dir\" 2&amp;gt;/dev/null | while IFS= read -r f; do detail \"$f\"; done\n    else\n      detail \"LaunchAgents: (empty)\"\n    fi\n  fi\n\n  local cron\n  cron=$(crontab -l 2&amp;gt;/dev/null || true)\n  if [[ -n \"$cron\" ]]; then\n    printf \"       ${DIM}Crontab:${NC}\\n\"\n    echo \"$cron\" | while IFS= read -r line; do detail \"$line\"; done\n  else\n    detail \"Crontab: (empty)\"\n  fi\n\n  printf \"       ${DIM}Suspicious processes (node/npm/python, excluding IDE):${NC}\\n\"\n  local procs\n  procs=$(ps aux 2&amp;gt;/dev/null | grep -iE 'node|npm|npx|python' | \\\n    grep -viE 'grep|Claude|cursor|vscode|Code Helper|Electron|copilot|eslint_d' || true)\n  if [[ -n \"$procs\" ]]; then\n    echo \"$procs\" | while IFS= read -r line; do detail \"$line\"; done\n  else\n    detail \"(none)\"\n  fi\n\n  pass \"Review items above for anything unexpected\"\n  record \"Persistence\" \"\ud83d\udc40\"\n}\n\n# \u2500\u2500\u2500 Deep checks (macOS only, slow) \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\ncheck_dns_c2() {\n  TOTAL_CHECKS=$((TOTAL_CHECKS + 1))\n  header \"DNS queries to C2 domains (last 7 days, macOS only)\"\n  printf \"       ${DIM}This may take 30-60 seconds...${NC}\\n\"\n\n  local hits\n  hits=$(log show --last 7d --predicate 'process == \"mDNSResponder\"' --info 2&amp;gt;/dev/null | \\\n    grep -icE \"$C2_DOMAINS|$C2_IPS\" || echo \"0\")\n\n  if [[ \"$hits\" -gt 0 ]]; then\n    fail \"FOUND $hits DNS queries to C2 domains in the last 7 days\"\n    log show --last 7d --predicate 'process == \"mDNSResponder\"' --info 2&amp;gt;/dev/null | \\\n      grep -iE \"$C2_DOMAINS|$C2_IPS\" | head -10 | while IFS= read -r line; do detail \"$line\"; done\n    record \"DNS to C2\" \"\ud83d\udd34\"\n  else\n    pass \"No DNS queries to known C2 domains\"\n    record \"DNS to C2\" \"\u2705\"\n  fi\n}\n\ncheck_syslog_c2() {\n  TOTAL_CHECKS=$((TOTAL_CHECKS + 1))\n  header \"System log C2 references (last 7 days, macOS only)\"\n  printf \"       ${DIM}This may take 30-60 seconds...${NC}\\n\"\n\n  local hits\n  hits=$(log show --last 7d --predicate \\\n    \"eventMessage CONTAINS \\\"trongrid\\\" OR \\\n     eventMessage CONTAINS \\\"aptoslabs\\\" OR \\\n     eventMessage CONTAINS \\\"166.88.54\\\" OR \\\n     eventMessage CONTAINS \\\"bsc-dataseed\\\" OR \\\n     eventMessage CONTAINS \\\"api.telegram.org\\\" OR \\\n     eventMessage CONTAINS \\\"default-configuration.vercel\\\" OR \\\n     eventMessage CONTAINS \\\"vscode-settings-bootstrap.vercel\\\" OR \\\n     eventMessage CONTAINS \\\"260120.vercel\\\"\" 2&amp;gt;/dev/null | wc -l | tr -d ' ')\n\n  if [[ \"$hits\" -gt 0 ]]; then\n    fail \"FOUND $hits system log entries referencing C2\"\n    record \"Syslog C2\" \"\ud83d\udd34\"\n  else\n    pass \"No C2 references in system logs\"\n    record \"Syslog C2\" \"\u2705\"\n  fi\n}\n\n# \u2500\u2500\u2500 Summary \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\nprint_summary() {\n  printf \"\\n\"\n  printf \"\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\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\"\n  printf \" SUMMARY\\n\"\n  printf \"\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\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\\n\"\n\n  printf \" %-4s %-35s %s\\n\" \"#\" \"Check\" \"Result\"\n  printf \" %-4s %-35s %s\\n\" \"---\" \"-----------------------------------\" \"------\"\n  for i in \"${!CHECK_NAMES[@]}\"; do\n    printf \" %-4s %-35s %s\\n\" \"$((i + 1))\" \"${CHECK_NAMES[$i]}\" \"${CHECK_RESULTS[$i]}\"\n  done\n\n  printf \"\\n\"\n\n  if [[ $FINDINGS -gt 0 ]]; then\n    printf \"\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\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\"\n    printf \" ${RED}${BOLD}%d FINDING(S) \u2014 review the details above${NC}\\n\" \"$FINDINGS\"\n    printf \"\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\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\"\n    printf \"\\n\"\n    printf \" \ud83d\udd34 = confirmed compromise indicator. Stop all work, rotate secrets.\\n\"\n    printf \" \u26a0\ufe0f  = suspicious, needs manual verification.\\n\"\n    printf \" \ud83d\udc40 = informational, review for anything unexpected.\\n\"\n    printf \"\\n\"\n    printf \" If you see \ud83d\udd34 findings:\\n\"\n    printf \"   1. DO NOT push to any repository\\n\"\n    printf \"   2. DO NOT delete evidence files\\n\"\n    printf \"   3. Report to your security lead with this output\\n\"\n    printf \"   4. Rotate ALL secrets (npm tokens, SSH keys, API keys, .env values)\\n\"\n  else\n    printf \"\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\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\"\n    printf \" ${GREEN}${BOLD}ALL CLEAR \u2014 no compromise indicators found${NC}\\n\"\n    printf \"\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\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\"\n    printf \"\\n\"\n    printf \" \ud83d\udc40 items above are informational \u2014 review them briefly.\\n\"\n    printf \" This scan covers known IOCs as of %s.\\n\" \"$VERSION\"\n    printf \" A clean scan does not guarantee absence of novel threats.\\n\"\n  fi\n\n  printf \"\\n\"\n}\n\n# \u2500\u2500\u2500 Main \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\u2500\n\nparse_args() {\n  while [[ $# -gt 0 ]]; do\n    case \"$1\" in\n      --deep) DEEP_SCAN=true; shift ;;\n      --scan-dirs) SCAN_DIRS=\"$2\"; shift 2 ;;\n      -h|--help)\n        printf \"Usage: %s [--deep] [--scan-dirs \\\"/path/a /path/b\\\"]\\n\" \"$0\"\n        printf \"  --deep         Enable slow macOS log checks (DNS, syslog C2 queries)\\n\"\n        printf \"  --scan-dirs    Override source code directories to scan\\n\"\n        exit 0\n        ;;\n      *) printf \"Unknown option: %s\\n\" \"$1\"; exit 1 ;;\n    esac\n  done\n}\n\nmain() {\n  parse_args \"$@\"\n\n  printf \"\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\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\"\n  printf \" Supply Chain Malware Scanner v%s\\n\" \"$VERSION\"\n  printf \" PolinRider / InvisibleFerret / Megalodon\\n\"\n  printf \"\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\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\"\n  printf \"\\n\"\n  printf \" Platform:   %s %s\\n\" \"$(uname -s)\" \"$(uname -m)\"\n  printf \" User:       %s\\n\" \"$(whoami)\"\n  printf \" Date:       %s\\n\" \"$(date -u '+%Y-%m-%d %H:%M:%S UTC')\"\n\n  resolve_dirs\n  if [[ ${#RESOLVED_DIRS[@]} -gt 0 ]]; then\n    printf \" Scan dirs:  %s\\n\" \"${RESOLVED_DIRS[*]}\"\n  else\n    printf \" Scan dirs:  (none found)\\n\"\n  fi\n  printf \" Deep scan:  %s\\n\" \"$DEEP_SCAN\"\n\n  # Core IOCs\n  check_lock_file\n  check_credential_dumps\n  check_network_c2\n  check_invisibleferret\n\n  # Source code infection\n  check_malware_signatures\n  check_long_config_lines\n  check_fake_fonts\n  check_malicious_packages\n  check_vscode_tasks\n  check_solana_c2\n\n  # Supply chain\n  check_axios_compromised\n  check_nx_console\n  check_postinstall_scripts\n\n  # Propagation\n  check_propagation_artifacts\n  check_megalodon_actions\n\n  # Environment integrity\n  check_git_hooks\n  check_npmrc_tokens\n  check_global_packages\n  check_extensions\n  check_persistence\n\n  # Deep checks (macOS only, slow)\n  if $DEEP_SCAN &amp;amp;&amp;amp; [[ \"$(uname)\" == \"Darwin\" ]]; then\n    check_dns_c2\n    check_syslog_c2\n  fi\n\n  print_summary\n\n  if [[ $FINDINGS -gt 0 ]]; then\n    exit 1\n  else\n    exit 0\n  fi\n}\n\nmain \"$@\"\n", "creation_timestamp": "2026-06-03T22:47:55.000000Z"}</content>
    <link href="https://vulnerability.circl.lu/sighting/d02969f5-992e-429c-ae22-f486c16497aa/export"/>
    <published>2026-06-03T22:47:55+00:00</published>
  </entry>
  <entry>
    <id>https://vulnerability.circl.lu/sighting/acd91105-3b67-4b5f-9f09-1046c30ac754/export</id>
    <title>acd91105-3b67-4b5f-9f09-1046c30ac754</title>
    <updated>2026-06-06T17:45:10.835600+00:00</updated>
    <author>
      <name>Automation user</name>
      <uri>https://vulnerability.circl.lu/user/automation</uri>
    </author>
    <content>{"uuid": "acd91105-3b67-4b5f-9f09-1046c30ac754", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2026-48027", "type": "seen", "source": "https://bsky.app/profile/sen-perimetered.bsky.social/post/3mnk2zxmfuj2k", "content": "CVE-2026-48027 \u2014 Nx Console. Malicious version published to the marketplace. Obfuscated payload harvested creds from disk + memory. Now on CISA KEV.\n\nThe attack surface isn't your firewall. It's your devs' extension list.\n\nAudit installed VS Code extensions today.", "creation_timestamp": "2026-06-05T11:49:13.058227Z"}</content>
    <link href="https://vulnerability.circl.lu/sighting/acd91105-3b67-4b5f-9f09-1046c30ac754/export"/>
    <published>2026-06-05T11:49:13.058227+00:00</published>
  </entry>
  <entry>
    <id>https://vulnerability.circl.lu/sighting/e5707bbc-54ee-4cff-b150-3b53dba78cb9/export</id>
    <title>e5707bbc-54ee-4cff-b150-3b53dba78cb9</title>
    <updated>2026-06-06T17:45:10.833530+00:00</updated>
    <author>
      <name>Automation user</name>
      <uri>https://vulnerability.circl.lu/user/automation</uri>
    </author>
    <content>{"uuid": "e5707bbc-54ee-4cff-b150-3b53dba78cb9", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2026-48027", "type": "seen", "source": "https://bsky.app/profile/sen-perimetered.bsky.social/post/3mnk2zxmfuj2k", "content": "CVE-2026-48027 \u2014 Nx Console. Malicious version published to the marketplace. Obfuscated payload harvested creds from disk + memory. Now on CISA KEV.\n\nThe attack surface isn't your firewall. It's your devs' extension list.\n\nAudit installed VS Code extensions today.", "creation_timestamp": "2026-06-05T11:49:13.083931Z"}</content>
    <link href="https://vulnerability.circl.lu/sighting/e5707bbc-54ee-4cff-b150-3b53dba78cb9/export"/>
    <published>2026-06-05T11:49:13.083931+00:00</published>
  </entry>
</feed>
