Security firm Aikido Security disclosed on March 13, 2026 that a threat group it named Glassworm uploaded 151 malicious packages to GitHub, npm, and Open VSX between March 3 and March 9. The packages exploit a novel evasion technique: malicious payloads are encoded using Unicode Private Use Area (PUA) code points — specifically Variation Selectors in the ranges U+FE00–U+FE0F and U+E0100–U+E01EF — that are completely invisible in every standard editor, terminal, and code review interface. At JavaScript runtime, a small decoder function extracts the real bytes from what appears to be an empty backtick string and passes them to eval(), executing a full second-stage payload. Static analysis tools and human reviewers see nothing. Security firm Koi, independently tracking the same campaign, corroborated Aikido's findings.
The <a href="/news/2026-03-15-supply-chain-attack-invisible-unicode-github-npm-open-vsx">suspected use of LLMs</a> is what sets Glassworm apart from typical supply-chain actors. The malicious injections are surrounded by realistic, project-appropriate changes — documentation tweaks, version bumps, minor refactors — that are stylistically consistent with each targeted codebase. Both Aikido and Koi assess that manually crafting 151 or more bespoke, convincing code modifications across different projects at this pace would be infeasible without AI assistance. Previously decoded payloads from the group used Solana as a delivery channel to exfiltrate tokens, credentials, and secrets, pointing to a financially motivated actor with cryptocurrency interests.
PUA code points were largely forgotten after their original use for vendor-specific glyphs and font extensions until 2024, when attackers repurposed them to smuggle malicious instructions into LLM input pipelines — text invisible to human supervisors but fully legible to language models. AI providers subsequently added guardrails against anomalous PUA usage, though those defenses have been periodically circumvented. Glassworm ran the same trick through a different interpreter: instead of feeding invisible instructions to an LLM, it feeds them to the JavaScript runtime. The evasion logic is identical; only the execution engine changed.