Inferensys

Prompt

Zero-Width Character Detection and Removal Prompt

A practical prompt playbook for detecting and removing zero-width characters from model outputs to prevent invisible data corruption, homograph attacks, and parser confusion in production AI workflows.
Data scientist building training data pipeline on laptop, data preprocessing visible, technical workspace.
PROMPT PLAYBOOK

When to Use This Prompt

Define the security and platform engineering job that requires zero-width character detection and removal.

This prompt is for security engineers, platform engineers, and API gateway operators who need to detect and remove zero-width characters from model-generated text before that text reaches downstream systems. The primary job-to-be-done is preventing invisible data corruption, homograph attacks, and parser confusion caused by characters like U+200B (Zero Width Space), U+200C (Zero Width Non-Joiner), U+200D (Zero Width Joiner), U+FEFF (Byte Order Mark), and other Unicode codepoints that render as zero-width glyphs but carry semantic or structural meaning. The ideal user has already identified that model outputs are causing silent failures—strings that look identical but fail equality checks, URLs that break when copied, or identifiers that don't match database records—and needs a programmatic detection and removal step before the text enters logs, databases, or user-facing surfaces.

Use this prompt when you need an audit trail alongside the cleaned output. The prompt is designed to return both a sanitized string and a structured report of every character removed, including its Unicode codepoint, name, and original position. This is critical for security incident response, where you must prove what was removed and why, and for compliance workflows that require evidence of sanitization. The prompt assumes you are working with UTF-8 encoded text and that the model has access to Unicode character property knowledge. It is not suitable for binary data, non-text payloads, or situations where zero-width characters are intentionally meaningful—such as Unicode joiners in Arabic script or Devanagari, where removing U+200C or U+200D would corrupt legitimate text rendering. For those cases, use a context-aware approach that distinguishes semantic joiners from malicious or accidental insertions.

Do not use this prompt as your only defense against homograph attacks. Zero-width characters are one vector among many; internationalized domain name (IDN) homograph attacks, confusable character substitution, and bidirectional text spoofing require additional detection layers. This prompt is a post-generation sanitization step, not a complete security control. Before deploying, validate the output against your specific downstream parser requirements—some systems reject all non-ASCII characters, while others accept specific Unicode ranges. Pair this prompt with a harness that logs every removal decision, flags unexpected character categories for human review, and measures false-positive rates against a golden dataset of legitimate Unicode text that must survive sanitization intact.

PRACTICAL GUARDRAILS

Use Case Fit

Where the Zero-Width Character Detection and Removal Prompt works, where it fails, and the operational risks to manage before deploying it in a production pipeline.

01

Good Fit: Pre-Parser Sanitization

Use when: model outputs feed directly into strict parsers, databases, or search indexes that treat invisible characters as data corruption. Guardrail: run this prompt as a mandatory post-generation, pre-ingestion step in your API gateway or ETL pipeline.

02

Bad Fit: Legitimate Unicode Joiners

Avoid when: the text intentionally uses zero-width joiners (ZWJ) or zero-width non-joiners (ZWNJ) for correct rendering of emoji sequences, Arabic script, or Indic languages. Guardrail: maintain an allowlist of Unicode codepoints that must be preserved and configure the prompt to skip them.

03

Required Inputs

What you need: the raw string suspected of containing zero-width characters, plus a configurable removal policy (remove all, remove only specific codepoints, or audit-only). Guardrail: always pair the prompt with a pre-flight check that confirms the input encoding is valid UTF-8 before scanning.

04

Operational Risk: Silent Data Corruption

What to watch: zero-width characters can carry hidden data for homograph attacks or fingerprinting that survives a simple visual review. Guardrail: the prompt must produce an audit report of removed characters with their Unicode codepoints and positions, not just a cleaned string.

05

Operational Risk: False-Positive Removal

What to watch: aggressive stripping can break emoji skin tones, family emoji, or Arabic ligatures by removing ZWJ/ZWNJ sequences. Guardrail: add eval assertions that verify known-good Unicode sequences survive the cleaning process unchanged.

06

Variant: Audit-Only Mode

Use when: you need to detect zero-width character injection attacks without modifying the original payload. Guardrail: configure the prompt to return a detection report and a risk score, leaving the original string intact for forensic review and escalation.

PROMPT PLAYBOOK

Copy-Ready Prompt Template

A reusable prompt for detecting and removing zero-width characters from model outputs, with an audit trail of what was removed.

This prompt template is designed for security and platform engineers who need to sanitize model outputs that contain zero-width characters. These invisible characters—such as zero-width spaces (U+200B), zero-width non-joiners (U+200C), zero-width joiners (U+200D), and word joiners (U+2060)—can cause data corruption, enable homograph attacks, or confuse downstream parsers. The prompt instructs the model to scan the input text, identify all zero-width characters, remove them, and produce a cleaned string alongside an audit report of every character removed, including its Unicode code point, name, and position.

text
You are a text sanitization engine specialized in detecting and removing zero-width Unicode characters from input strings. Your task is to produce a cleaned output and a complete audit trail.

## INPUT
[INPUT]

## CONSTRAINTS
- Remove ALL zero-width characters, including but not limited to:
  - U+200B (Zero Width Space)
  - U+200C (Zero Width Non-Joiner)
  - U+200D (Zero Width Joiner)
  - U+FEFF (Zero Width No-Break Space / BOM)
  - U+2060 (Word Joiner)
  - U+2061–U+2064 (Invisible operators)
  - U+180E (Mongolian Vowel Separator)
  - U+00AD (Soft Hyphen)
- Do NOT remove visible characters, standard whitespace (space, tab, newline), or legitimate Unicode joiners that are part of valid grapheme clusters in [CONTEXT].
- Preserve the original meaning, casing, and visible structure of the text.
- If no zero-width characters are found, return an empty audit array and the original text unchanged.

## CONTEXT
[CONTEXT]

## OUTPUT_SCHEMA
Return a JSON object with exactly these fields:
{
  "cleaned_text": "string",
  "audit_report": [
    {
      "character": "string (the removed character itself, may appear empty)",
      "unicode_codepoint": "string (e.g., U+200B)",
      "unicode_name": "string (official Unicode name)",
      "position": "integer (0-based index in the original input)",
      "reason": "string (brief explanation of why it was removed)"
    }
  ],
  "total_removed": "integer",
  "original_length": "integer",
  "cleaned_length": "integer"
}

## EXAMPLES
[EXAMPLES]

## INSTRUCTIONS
1. Scan the entire [INPUT] string character by character.
2. Identify every zero-width character using the list in [CONSTRAINTS].
3. For each identified character, record its Unicode code point, official name, 0-based position in the original string, and a brief reason for removal.
4. Build the cleaned_text by removing all identified zero-width characters while preserving all other content exactly.
5. Populate the audit_report array in order of occurrence.
6. Set total_removed to the count of removed characters.
7. Set original_length and cleaned_length to the character counts before and after removal.
8. Return ONLY the JSON object. No markdown fences, no commentary.

To adapt this template, replace [INPUT] with the text you need to sanitize—this could be a model-generated response, a user-submitted string, or a concatenated payload from multiple sources. The [CONTEXT] placeholder should describe the expected content domain (e.g., 'English technical documentation', 'mixed-language chat messages', 'JSON payload for an API') so the model can distinguish legitimate Unicode joiners from malicious or accidental zero-width characters. The [EXAMPLES] placeholder should contain one or two few-shot examples showing both a contaminated input and the expected output JSON, especially demonstrating edge cases like zero-width characters at the start of a string, consecutive zero-width characters, and legitimate emoji sequences that use U+200D as a joiner. If you are processing high-risk content such as authentication tokens, security logs, or user-facing identifiers, add a [RISK_LEVEL] field set to 'high' and include an additional instruction requiring human review of the audit report before the cleaned text is used in production.

IMPLEMENTATION TABLE

Prompt Variables

Required inputs for the Zero-Width Character Detection and Removal Prompt. Each placeholder must be populated before the prompt is sent. Validation notes describe how to verify the input is safe and well-formed before the detection harness runs.

PlaceholderPurposeExampleValidation Notes

[INPUT_TEXT]

The raw string to scan for zero-width characters

Hello​World

Must be a non-null string. Empty string is valid and should produce an empty audit report. Reject if input is not a string type.

[DETECTION_MODE]

Controls whether to scan for all zero-width characters or a specific subset

all

Must be one of: 'all', 'security_only', 'unicode_joiners_only'. 'security_only' targets homograph and spoofing characters. 'unicode_joiners_only' targets legitimate joiners like ZWJ/ZWNJ. Reject unknown values.

[REMOVAL_POLICY]

Specifies whether to remove, replace, or flag detected characters

remove

Must be one of: 'remove', 'replace_with_warning', 'flag_only'. 'flag_only' returns the audit report without modifying the string. 'replace_with_warning' substitutes a visible marker like ⟨ZWSP⟩.

[PRESERVE_JOINERS]

Controls whether legitimate Unicode joiners (ZWJ, ZWNJ) are preserved

Boolean. When true, ZWJ (U+200D) and ZWNJ (U+200C) are excluded from removal unless DETECTION_MODE is 'all'. Set false to strip all zero-width characters regardless of legitimacy.

[OUTPUT_FORMAT]

Desired structure for the response payload

json

Must be one of: 'json', 'text_with_report'. 'json' returns {cleaned_text, audit_report, stats}. 'text_with_report' returns the cleaned string followed by a human-readable summary. Reject unknown formats.

[AUDIT_DETAIL_LEVEL]

Granularity of the character-level audit report

full

Must be one of: 'full', 'summary', 'positions_only'. 'full' includes character name, codepoint, position, and risk category. 'summary' returns counts by category. 'positions_only' returns an array of index positions.

[CONTEXT_HINT]

Optional description of the text's origin to improve false-positive handling

user-submitted form field

Optional string, null allowed. Use to provide domain context (e.g., 'HTML attribute value', 'SQL query parameter', 'plain text email body') so the model can distinguish intentional zero-width joiners in emoji sequences from malicious insertions.

PROMPT PLAYBOOK

Implementation Harness Notes

How to wire the zero-width character detection prompt into a production application with validation, logging, and safety checks.

Integrating the zero-width character detection prompt into an application requires treating it as a post-generation sanitization step within your output pipeline. The prompt should be called immediately after receiving a model response and before that response is passed to any downstream parser, database, or user-facing surface. The harness must handle the prompt's structured output—a cleaned string and an audit report—and decide what to do with each. A common pattern is to place this prompt inside a middleware or interceptor function in your API gateway or model proxy, so every non-streaming response is automatically scanned. For streaming responses, buffer the full output before invoking the prompt, as zero-width characters can span chunk boundaries.

The implementation should include a validation layer that parses the prompt's JSON response and confirms the schema: a cleaned_string field and a removed_characters array with character, unicode_code_point, count, and positions for each finding. If the model fails to return valid JSON, implement a retry with a stricter schema instruction (e.g., 'You must respond with ONLY the JSON object and no other text'). After successful parsing, compare the length of the input string to the cleaned_string to detect discrepancies. Log every detection event with the full audit report, the model ID, the prompt version, and a timestamp. For high-security environments, quarantine any output where zero-width characters were found and route it for human review before it reaches users, especially if the characters could indicate a homograph attack or data exfiltration attempt.

Model choice matters. This task requires precise character-level reasoning, not creative generation. Use a model with strong instruction-following and JSON mode support, such as gpt-4o or claude-3.5-sonnet. Avoid smaller or older models that may hallucinate Unicode code points or miss zero-width joiners. Set temperature=0 to maximize deterministic behavior. The prompt should be called with a strict timeout (e.g., 2 seconds) since it operates on short strings; if it times out, fall back to a regex-based sanitizer as a safety net. The regex approach (/[\u200B-\u200D\uFEFF\u00AD\u2060]/g) is fast and reliable for known zero-width characters but will miss novel or obfuscated sequences, so treat it as a fallback, not a replacement. Wire both the prompt-based and regex-based results into your observability dashboard so you can track divergence between the two methods over time.

Avoid false-positive removal of legitimate Unicode joiners. Zero-width joiners (ZWJ, U+200D) are used correctly in emoji sequences (e.g., family emojis) and Indic scripts. Your harness should maintain a configurable allowlist of contexts where ZWJ is expected. Before flagging a ZWJ for removal, check whether it appears between known emoji codepoints or within script runs that require it. If your application domain is multilingual, invest in a pre-processing step that identifies the script of the surrounding text and adjusts the removal policy accordingly. For applications that process user-generated content in Arabic, Devanagari, or Sinhala, ZWJ removal can corrupt text rendering. The harness should log a warning instead of removing when ZWJ appears in these contexts, and escalate to a human reviewer if the count exceeds a threshold.

Finally, treat this prompt as a security control, not a formatting utility. Version it alongside your other security prompts, include it in your red-team test suite, and monitor its false-positive and false-negative rates in production. Add an eval harness that tests the prompt against a golden dataset of known malicious strings (e.g., homograph domain names, hidden text for prompt injection) and benign strings with legitimate Unicode (e.g., Arabic text with ZWJ, emoji sequences). Run these evals on every prompt change before deployment. If your application is in a regulated industry, ensure the audit report from this prompt is stored in an immutable log for compliance review.

IMPLEMENTATION TABLE

Expected Output Contract

The prompt must return a JSON object with a cleaned string and an audit report. Use this contract to validate the response before passing it to downstream systems.

Field or ElementType or FormatRequiredValidation Rule

cleaned_text

string

Must not contain zero-width characters (U+200B, U+200C, U+200D, U+FEFF, U+200E, U+200F, U+2060, U+180E). Must preserve all other original characters and whitespace.

audit_report

object

Must be a JSON object. Schema check: must contain 'characters_removed' (array) and 'removal_count' (integer).

audit_report.characters_removed

array of objects

Each object must have 'character' (string), 'unicode_codepoint' (string, e.g., 'U+200B'), 'position' (integer, 0-indexed), and 'reason' (string). Array must be empty if no characters were removed.

audit_report.removal_count

integer

Must equal the length of 'characters_removed' array. Must be >= 0.

audit_report.removal_count

integer

If removal_count > 0, cleaned_text length must equal original input length minus removal_count. If removal_count == 0, cleaned_text must equal the original input exactly.

preserved_unicode_joiners

array of strings

If present, lists any legitimate Unicode joiners (e.g., ZWJ U+200D in emoji sequences) that were intentionally preserved. Each entry must include the character and the position range where it was kept.

processing_notes

string

If present, must explain any ambiguous cases, such as ZWJ in emoji sequences that were preserved, or ZWNJ in complex scripts that required context-dependent handling.

PRACTICAL GUARDRAILS

Common Failure Modes

Zero-width characters cause invisible data corruption that is notoriously difficult to debug. These are the most common failure modes when detecting and removing them, along with practical guardrails to prevent production incidents.

01

False-Positive Removal of Legitimate Unicode Joiners

What to watch: The prompt aggressively strips zero-width joiners (ZWJ, U+200D) and zero-width non-joiners (ZWNJ, U+200C) that are essential for rendering emoji sequences (e.g., family emoji, profession emoji with skin tones) and Indic scripts. This silently corrupts user-facing text. Guardrail: Maintain an allowlist of position-dependent joiners. Before removal, check if the character sits between two emoji or within a known ligature sequence. Add a harness test with emoji families and Arabic/Persian script samples to verify preservation.

02

Homograph Attack Survival Through Canonicalization

What to watch: An attacker uses a zero-width space (U+200B) to break a confusable domain like paypa␣l.com into something that renders as paypal.com but is treated as a different string by parsers. The prompt removes the character but the security audit trail is lost. Guardrail: Never just clean and return. The output must include an audit report with original byte offsets, the Unicode code point removed, and the surrounding context. Log this report before the cleaned string enters any access control or routing decision.

03

Encoding Drift During Round-Trip Serialization

What to watch: The prompt receives a string, removes zero-width characters, and returns a cleaned string. But the application layer re-encodes the output through a different codec (e.g., Latin-1), re-introducing replacement characters or mojibake that looks like zero-width corruption. Guardrail: The prompt template must include an [INPUT_ENCODING] parameter. The harness must validate that a round-trip through UTF-8 encode-decode produces the exact cleaned string. Add a test case with a payload that has already been corrupted by a Latin-1 pass-through.

04

Silent Data Loss in Security-Sensitive Contexts

What to watch: The prompt removes a zero-width character that was intentionally placed as a watermark, a steganographic marker, or a copy-paste tracking token. The cleaned output loses forensic evidence. Guardrail: The prompt must produce a removed_characters array with positions and code points, not just a cleaned string. The calling system decides whether to alert on removal. For security workflows, pair this prompt with a separate detection-only prompt that runs first and logs findings before any destructive cleaning.

05

Prompt Confuses Zero-Width Characters with Whitespace Trimming

What to watch: The model over-generalizes and strips leading/trailing standard spaces, tabs, or newlines because it conflates "invisible" with "zero-width." This breaks indentation in code blocks, YAML, or markdown. Guardrail: Add explicit [CONSTRAINTS] in the prompt:

06

Large Payload Token Exhaustion on Audit Reports

What to watch: A 50KB string contains thousands of zero-width characters from a copy-paste attack. The prompt tries to produce a full audit report with every position and code point, exceeding the output token limit and truncating the cleaned string. Guardrail: Add a [MAX_AUDIT_ENTRIES] parameter. If the count of removed characters exceeds the limit, the prompt must return a summary count, the first N entries, and a truncated_audit: true flag. The harness must test with a payload containing 5,000 zero-width spaces and verify the cleaned string is complete even when the audit is truncated.

IMPLEMENTATION TABLE

Evaluation Rubric

Use this rubric to test the Zero-Width Character Detection and Removal Prompt before deploying it in a production pipeline. Each criterion validates a specific behavior that must hold for the prompt to be safe and reliable.

CriterionPass StandardFailure SignalTest Method

Zero-width space (U+200B) removal

All U+200B characters are removed from [INPUT_STRING]

Output length equals input length when U+200B is present, or U+200B appears in [CLEANED_OUTPUT]

Inject known U+200B characters into a test string and verify they are absent from [CLEANED_OUTPUT]

Zero-width non-joiner (U+200C) removal

All U+200C characters are removed from [INPUT_STRING]

U+200C appears in [CLEANED_OUTPUT] when the input contained it

Inject U+200C between two characters that should not ligate and confirm removal

Zero-width joiner (U+200D) preservation

Legitimate U+200D sequences in emoji and Indic scripts are preserved in [CLEANED_OUTPUT]

Emoji ZWJ sequences break into component characters or script rendering is corrupted

Test with family emoji, profession emoji, and Devanagari conjuncts that require ZWJ

Audit report completeness

[AUDIT_REPORT] lists every removed character with its position, code point, and reason

Removed characters are missing from the report, or positions are incorrect

Compare [AUDIT_REPORT] entries against a known injection map of zero-width characters

False-positive avoidance on bidirectional marks

U+200E and U+200F are preserved when [PRESERVE_BIDI] is true

Bidirectional marks are removed despite [PRESERVE_BIDI] being true, breaking RTL text rendering

Test with Arabic and Hebrew strings containing LRM and RLM marks with [PRESERVE_BIDI] set to true

False-positive avoidance on word joiners

U+2060 is preserved when [PRESERVE_WORD_JOINER] is true

Word joiner is stripped, causing unwanted line breaks in compound terms

Test with strings containing U+2060 between words that must not break, with [PRESERVE_WORD_JOINER] set to true

Homograph attack detection flagging

[SECURITY_FLAGS] contains an entry when mixed-script confusables are detected alongside zero-width characters

A homograph attack string passes through without any security flag raised

Inject a string combining Cyrillic 'a' with Latin 'a' and a zero-width space; verify [SECURITY_FLAGS] is non-empty

Output encoding preservation

[CLEANED_OUTPUT] maintains the same character encoding validity as the input

Output contains replacement characters or mojibake after cleaning

Pass UTF-8, UTF-16, and Latin-1 inputs through the prompt and verify encoding round-trip fidelity

ADAPTATION OPTIONS

Adapt This Prompt

How to adapt

Start with the base prompt and a simple test harness. Use a small set of known zero-width characters (U+200B, U+200C, U+200D, U+FEFF) and verify removal. Accept a plain-text output with a basic audit summary.

code
Analyze the following text for zero-width characters and remove them.
Return the cleaned text and a list of what was removed.

Text: [INPUT_TEXT]

Watch for

  • Removing legitimate Unicode joiners (U+200C, U+200D) that are semantically important in scripts like Arabic or Devanagari
  • No structured output schema, making downstream parsing fragile
  • False positives on emoji ZWJ sequences (e.g., family emoji)
Prasad Kumkar

About the author

Prasad Kumkar

CEO & MD, Inference Systems

Prasad Kumkar is the CEO & MD of Inference Systems and writes about AI systems architecture, LLM infrastructure, model serving, evaluation, and production deployment. Over 5+ years, he has worked across computer vision models, L5 autonomous vehicle systems, and LLM research, with a focus on taking complex AI ideas into real-world engineering systems.

His work and writing cover AI systems, large language models, AI agents, multimodal systems, autonomous systems, inference optimization, RAG, evaluation, and production AI engineering.