Safeguard
Application Security•

Detecting and Mitigating Invisible Unicode in Code (T1027.018)

Zero width and other non printing characters can hide an encoded payload inside text that looks blank. Learn how it works and how to scan your own files for it.

Safeguard Security Team
4 min read

A script can look like a few harmless lines, or even like empty space, and still carry a hidden payload. The trick is Unicode characters that take up bytes but draw nothing on screen.

MITRE tracks this as Invisible Unicode, technique T1027.018, a sub-technique of Obfuscated Files or Information in the Stealth tactic. It applies to Linux, macOS and Windows.

How attackers use it

Unicode assigns a code point to every character in every writing system. Some valid code points are not rendered visibly: zero-width spaces, variation selectors and bidirectional formatting controls. MITRE says adversaries abuse these to hide data, change how content is interpreted, or make malicious code look like benign text or whitespace.

The hidden content may be encoded in binary, Base64 or a custom scheme, then rebuilt at run time with scripting features such as JavaScript Proxy traps, eval() or other dynamic execution. Private Use Area (PUA) characters, a range reserved for custom assignment, are another option. If no font or application defines them, they usually render blank.

The same characters also support other techniques, such as phishing and right-to-left override.

The effect is that code review by eye fails. The reviewer sees nothing wrong because there is nothing to see.

How to detect it

MITRE's strategy (DET0920) has three analytics. All look for a file that looks plain but behaves otherwise:

  • Windows. Scripts or files with a low ratio of printable characters that decode and dynamically evaluate content at run time, then start processes or open network connections.
  • Linux and similar. Scripts with a high concentration of invisible Unicode followed by decoding or interpretation steps such as base64 decode or eval, then process or network activity. A mismatch between file entropy and structure and what the script outputs is a hint.
  • macOS. Scripts or apps with invisible Unicode payloads rebuilt at run time, with unusual AppleScript, JavaScript for Automation or shell execution and network behavior that the visible text does not explain.

For source code, the most practical control is a scan in your repository and pull request flow. Look for any non-printing characters in files that should be plain text. Legitimate uses exist in some languages and documents, so allowlist deliberately rather than ignoring the finding.

How to reduce the risk

MITRE lists no specific mitigation for this sub-technique. Sensible steps:

  1. Scan source and scripts for invisible and bidirectional characters before merge.
  2. Make your editor and code review tool display them. Many editors can be set to show hidden characters.
  3. Treat dynamic evaluation in scripts as a review flag, especially when paired with encoded strings.
  4. Check third party packages and scripts before you run them. The free in-browser dependency scan needs no login, the file never leaves your machine and it covers up to 100 dependencies.

Check your own environment

A read-only scan for common invisible code points. This Python script works on Linux, macOS and Windows. It lists file names and line numbers only.

import os, re, sys
pat = re.compile('[​-‏‪-‮⁠-⁤︀-️-]')
for root, dirs, files in os.walk(sys.argv[1]):
    for name in files:
        path = os.path.join(root, name)
        try:
            with open(path, encoding='utf-8') as f:
                for n, line in enumerate(f, 1):
                    if pat.search(line):
                        print(path, n)
        except (UnicodeDecodeError, OSError):
            pass

Run it as python3 scan.py path/to/repo. Expect some hits from legitimate files, such as a byte order mark at the start of a file or emoji variation selectors, and review each one.

Then ask:

  • Does your pull request pipeline flag hidden or bidirectional characters?
  • Do your editors show them?
  • Which scripts in your build use eval or similar dynamic execution, and who reviews them?

Try it yourself

Click through it at your own pace, or open it full screen.

Quick check

Why does visual code review miss invisible Unicode?

The characters take up bytes but draw nothing, so the text looks blank or harmless while the file still holds encoded content that a script can rebuild and run.

What run time features does MITRE say rebuild the hidden payload?

Scripting features such as JavaScript Proxy traps, eval and other dynamic execution methods.

Sources

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.