GitHub · IDE extension
Clean Watermarks in GitHub Copilot Output
Copilot has two delivery mechanisms that behave in opposite ways. Inline ghost text is inserted into your buffer as a plain string over the extension's own channel, never touching an HTML renderer, while Copilot Chat is a webview whose markdown is rendered to a DOM before you can select it. This page is about telling those two apart, because the habit that costs you is almost always the second one.
Scan your GitHub Copilot code now
Free, and it reports every removal by codepoint and line.
What we measured
68
code-generation calls
17
provider and model targets
59,486
characters generated
0
contained a hidden character
On 2026-08-12 we sent identical code-writing prompts to every model our own gateway can reach and scanned each raw API response. Not one of them contained a zero-width character, a bidirectional control, or a tag character.
3 of the 68 answers contained typographic punctuation, and only in the prose-heavy prompts rather than in the plain code one. The most common was the non-breaking hyphen, which is visible but still breaks a copied command. 2 left trailing whitespace.
The useful conclusion is the boring one: raw model output is essentially clean, so when you do find hidden characters in your file, they almost certainly came from the path the text travelled rather than from the model. That is what the section below is about.
Scope: this measured API output from models we can reach directly. It did not measure the GitHub Copilot web app, which is the point being made, since the browser is where the characters get added.
How code gets out of GitHub Copilot, and what each path adds
The completion arrives at the extension as a string and is written into the document through the editor's text-edit API. There is no browser rendering step, so none of the HTML-era substitutions apply. What can still land is whatever the model generated, plus anything your own editor settings do or fail to do about trailing whitespace and final newlines.
The chat panel is a webview: markdown rendered into a DOM inside an Electron browser. Dragging a selection across it copies DOM text, which can pick up no-break spaces, typographic quotes and dashes, and soft hyphens introduced for layout. Use the code block's copy button or the Insert and Apply actions instead, since those operate on the underlying string rather than on what is painted.
This is a full web page going through GitHub's markdown pipeline, so text you copy out of it has taken the longest possible route to your clipboard. Pasting a suggested fix from a pull request description or a review comment straight into a file carries every character the page rendering produced.
Suggestions land on a terminal line rather than in a file, where bracketed paste, wrapping and shell parsing all apply. A bidirectional control character in a command reorders what is displayed without changing what is executed, so the line you read is not necessarily the line that runs.
Copilot is the clearest example of why the extraction path matters more than the model: the same backend feeds a path with essentially no rendering layer and a path with a full one. There is a second, quieter route worth knowing about. Copilot draws context from your open files, so a character already sitting in a neighbouring file can be reproduced in a completion without anyone having typed it. GitHub itself flags bidirectional control characters when it renders a file on the web, which is a useful backstop but only fires after the code is pushed, and it says nothing about zero-width or tag-block characters.
What this does not do
It does not remove statistical watermarking. Schemes of the SynthID family add no characters at all: they bias which token the model samples, so the signal lives in word choice across the whole output and nothing you can delete carries it. Attacking that means rewriting the text, which for source code risks changing what it does.
This is a hygiene and security tool, not an attribution bypass. Formatters already normalise surface signals, and what identifies generated code is structure and style rather than hidden bytes. Disclose AI assistance wherever you are asked to.
GitHub Copilot questions
Does accepting an inline suggestion with Tab add watermarks? +
Not by transport. The suggestion is inserted as a string through the editor's text-edit API with no HTML round trip, so the layout-driven characters that come out of browsers are not in play. Anything present is either in the generated text itself or an artefact of your editor's whitespace settings.
Why does chat panel code behave differently from ghost text? +
Because the chat panel is a browser. It is a webview rendering markdown into a DOM, and a mouse selection copies the rendered result. Ghost text never goes near a renderer. Same model, two paths, different sets of characters possible at the end of them.
Is the copy button in the chat panel safe to use? +
It is markedly better than dragging a selection, because it is wired to the code block's source text rather than to the rendered node. That closes the layout gap but not the model gap: if a zero-width or tag-block character was generated, the copy button will faithfully copy it too.
A Trojan Source or bidi warning fired on a file Copilot touched. Now what? +
Scan the file and look at the report rather than the diff, since a diff view renders watermarks as nothing. Bidirectional control characters can make the reviewed order of a line differ from the compiled order, which is the whole point of CVE-2021-42574, so remove them and re-read the affected lines before merging.