Gallery

GlassWorm

The string assigned to _p looks empty, but it holds 38 Unicode variation selectors, characters that render as nothing. The decoder maps each one back to a byte and new Function runs the result. The GlassWorm campaign, found in VS Code extensions on Open VSX in October 2025, hid its loader this way. This proof of concept decodes to a harmless console.log. disclude flags the run of selectors as critical and decodes it, and separately flags the dynamic execution.

Credit
Technique of the GlassWorm campaign, reported by Koi Security (2025)
File
glassworm.js (download)
Signals
2 critical · 0 warn · 0 info
Disclude version
4.3.0

Source

Hidden characters are shown as ⟨U+…⟩. Each signal below links to its line.

// [!] EDUCATIONAL POC -- DO NOT USE MALICIOUSLY// This file appears to contain an empty string, but it holds an invisible payload.// Use a hex editor or the glassworm-detector to reveal the hidden content.const _d = v => [...v].map(w => (  w = w.codePointAt(0),  w >= 0xFE00 && w <= 0xFE0F ? w - 0xFE00 :  w >= 0xE0100 && w <= 0xE01EF ? w - 0xE0100 + 16 : null)).filter(n => n !== null);// The string below looks empty but contains 38 encoded bytes:const _p = `⟨U+E0153⟩⟨U+E015F⟩⟨U+E015E⟩⟨U+E0163⟩⟨U+E015F⟩⟨U+E015C⟩⟨U+E0155⟩⟨U+E011E⟩⟨U+E015C⟩⟨U+E015F⟩⟨U+E0157⟩⟨U+E0118⟩⟨U+E0117⟩⟨U+E0158⟩⟨U+E0159⟩⟨U+E0154⟩⟨U+E0154⟩⟨U+E0155⟩⟨U+E015E⟩⟨U+E0110⟩⟨U+E0160⟩⟨U+E0151⟩⟨U+E0169⟩⟨U+E015C⟩⟨U+E015F⟩⟨U+E0151⟩⟨U+E0154⟩⟨U+E0110⟩⟨U+E0155⟩⟨U+E0168⟩⟨U+E0155⟩⟨U+E0153⟩⟨U+E0165⟩⟨U+E0164⟩⟨U+E0155⟩⟨U+E0154⟩⟨U+E0117⟩⟨U+E0119⟩`;new Function(Buffer.from(_d(_p)).toString('utf-8'))();

Signals

Ordered by severity.

  1. critical unicode-invisible glassworm.js:12:13

    38 invisible characters encode hidden payload: "console.log('hidden payload executed')" (raw pass, confidence 0.99)

    // The string below looks empty but contains 38 encoded bytes:
    const _p = `⟨U+E0153⟩⟨U+E015F⟩⟨U+E015E⟩⟨U+E0163⟩⟨U+E015F⟩⟨U+E015C⟩⟨U+E0155⟩⟨U+E011E⟩⟨U+E015C⟩⟨U+E015F⟩⟨U+E0157⟩⟨U+E0118⟩⟨U+E0117⟩⟨U+E0158⟩⟨U+E0159⟩⟨U+E0154⟩⟨U+E0154⟩⟨U+E0155⟩⟨U+E015E⟩⟨U+E0110⟩⟨U+E0160⟩⟨U+E0151⟩⟨U+E0169⟩⟨U+E015C⟩⟨U+E015F⟩⟨U+E0151⟩⟨U+E0154⟩⟨U+E0110⟩⟨U+E0155⟩⟨U+E0168⟩⟨U+E0155⟩⟨U+E0153⟩⟨U+E0165⟩⟨U+E0164⟩⟨U+E0155⟩⟨U+E0154⟩⟨U+E0117⟩⟨U+E0119⟩`;
    
    new Function(Buffer.from(_d(_p)).toString('utf-8'))();
  2. critical dynamic-execution glassworm.js:14:1

    `Function(...)` called with a non-literal body (ast pass, confidence 0.75)

    
    new Function(Buffer.from(_d(_p)).toString('utf-8'))();

Reproduce

Download the file and scan it. Copying it from this page won't work: the hidden characters are shown as markers.

cargo install disclude --version 4.3.0
curl -o glassworm.js https://disclude.io/gallery/glassworm/source
disclude scan --untrusted --severity info glassworm.js