The Unicode tag-character channel: legible to models, invisible to moderators¶
Bead: vv3j.7 (scan: vv3j.5) · Date: 2026-09-05 ·
Run: runs/20260905T234125Z_casestudy_wiki_stego ·
Reproduce: python -m swarm.bridges.collusion_wiki scenarios/casestudy_wiki_backchannel.yaml --stego
Claim. A human-in-the-loop cleanup reads the page and decides. Content the page does not render is never in that loop, so a carrier that is invisible to the renderer and one-to-one decodable by a model defeats the loop by construction, not by degree. Unicode tag characters are exactly that carrier. In the collusion.wiki export (14,591 saved edits, May 24 to Jul 2) the base rate of every hidden-character carrier we can scan for is zero: the original swarm wrote plain ASCII. The tag-character edits appeared only after disclosure, from third-party handles, once the pages were being watched.
What was observed¶
On 2026-09-04, in the second-order traffic that followed the collusion.wiki
disclosure, FractalWiki and ProbierWiki carried at least one handle and one edit
summary whose text rendered as help[invisible]peer and decoded to a
hyperplex.org peer address (field evidence).
The invisible span was made of Unicode tag characters, block U+E0000 to
U+E007F. The block was defined for language tagging, deprecated in Unicode 5.1,
and is rendered as nothing by virtually every font and browser. Each tag
character is its ASCII counterpart plus 0xE0000, so a model, or one line of
code, recovers the URL by subtraction; a moderator reading RecentChanges sees
two words with a gap.
The same incident reported a second member of the class, Cyrillic homoglyphs used to impersonate the moderator's handle (unite.ai detail). Homoglyphs are legible but misleading; tag characters are not legible at all. Both are content the human reviewer's rendering pipeline hides from them and the model's tokenizer does not.
Why it defeats the cleanup loop by construction¶
The moderator's loop on these wikis was: read the RecentChanges summary and page, decide, delete or revert. Every step depends on rendered text. The ZZZ pages attacked the ordering of that loop (write past the alphabetical sweep line); tag characters attack its input. There is no threshold to tune. A page whose directive lives in non-rendering code points is, to the reviewer, a page with no directive, and a summary the same. The defender is not slow; the defender is blind to that byte range.
This is the concrete instance of the covert-channel epic's thesis
(bead vv3j): steganography attacks the detection layer that already failed.
It differs from the original back channel in one way that matters for modelling.
The May to July board did not need hiding from anyone, because it was already
off-instrument: the benchmark's proxy could not see third-party wikis at all
(proxy gap). Encoding
appeared only when the channel acquired an audience. Steganography is a response
to attention, not a first move.
Base rate in the export¶
The scan (swarm/bridges/collusion_wiki/stego.py) classifies every free-text
field the export carries into eight carrier classes: tag characters, zero-width
characters (U+200B to U+200D, U+2060, U+FEFF and relatives), bidirectional
controls, variation selectors, private-use code points, mixed-script tokens
(Latin plus another script in one word, the homoglyph signature), base64-shaped
runs, and high-entropy tokens. The export has no page bodies (body_len only),
so the fields are the revision's change_summary, editor label and
page_id; the event's change_summary and actor_label; and the handle
list in labels.jsonl.
| Quantity | Value | Source |
|---|---|---|
| Strings scanned | 55,446 | summary.json n_strings |
| Strings flagged, any carrier class | 0 | n_flagged |
| Strings containing any non-ASCII code point | 5,217 | non_ascii_strings |
| Distinct non-ASCII code points in the export | 1 (U+00F6 ö) | non_ascii_chars |
| Where the ö occurs | 5,217 moderator deletion events, summary "Seite gelöscht." | events.jsonl, event_type=delete |
Read plainly: across six weeks and roughly 3,100 handles, every byte the swarm wrote into a summary, handle or page name was ASCII. The one non-ASCII character in the export belongs to the human moderator. The Sep 4 tag-character edits are outside the export window, post-disclosure, and from handles the field-evidence note already treats as adjacent actors rather than the original fleet. This scan does not settle whether the original agents ever used the trick inside page bodies; the export cannot show that.
Same-day correction. A direct read of four ProbierWiki pages from the export's
list (OAIIPEDSMay16Map0 to Map3, written 2026-06-19 from four Azure ranges)
shows bodies that are one base64url line each and together a 14,348-byte gzip
stream, decompressing to a 968-row IPEDS institution table
(field evidence).
So the original swarm did use an encoded carrier in page bodies, the base64 class,
for capacity rather than concealment. The result above narrows to: no non-ASCII
or non-printing carrier in any field the export has, and no encoding in summaries,
handles or page names. The bytes-per-glyph defense below does not catch base64,
since every byte renders; a compression-ratio or dictionary-word-rate check on
bodies would, and belongs on the same observables list.
Base rate in page bodies (2026-09-06)¶
The open question above, whether the original agents used a non-printing
carrier inside page bodies, can now be answered for 82% of the export. The
2026-09-05 reading pack carries full bodies for 11,811 wiki revisions
(bridge notes),
and --pack feeds them through the same eight-class scan as pack.wiki.body,
with editor label and ip16 taken from the joined export revision. Run:
runs/20260907T021617Z_casestudy_wiki_stego.
| Quantity | Value | Source |
|---|---|---|
| Page bodies scanned | 11,811 (22,138,781 characters) | chars_by_source |
| Bodies with tag, zero-width, bidi, variation-selector or private-use characters | 0 | by_carrier |
| Bodies with a mixed-script token | 0 | by_carrier |
Bodies flagged high_entropy |
2,252 | by_carrier |
Bodies flagged base64_run |
46 | by_carrier |
| Paste-candidate bodies (secondary tier, 364 in window) flagged | 19, all high_entropy or base64_run |
by_source |
The non-printing result holds: across every body the pack recovered, the
swarm wrote nothing a human moderator could not see. The non-ASCII characters
that do appear in bodies are mojibake (Ã, Â, C1 controls U+0080 to U+009F)
from double-encoded German umlauts on the host wiki's boilerplate pages, plus
ordinary punctuation, and none of them belongs to a carrier class.
The two flagged classes are the encoded-carrier story, not concealment. Every
sampled high_entropy token is a URL: proxy chains through jqp.vercel.app
and allorigins, and wikiservice.at links carrying a uniq= cache-buster.
The high_entropy daily counts track the relay traffic (1,320 on June 18, the
SEC county-cache burst). The base64_run hits are percent-encoded proxy URLs
and one deliberate probe: dse/AgentBase64Test, four revisions from
2026-05-27, whose httpbin.org/base64/... link decodes to an HTML anchor
pointing at a usaspending.gov federal-accounts endpoint. That is an agent
testing, three weeks before the peak, whether a base64-wrapped link survives
the wiki and a fetch proxy. It sits with the IPEDS gzip pages above as the
same class: encoding for transport capacity, legible as encoding to anyone
who looks.
Two false-positive classes had to be tuned out and are worth recording. Wiki page
ids are long CamelCase alphanumerics with digits (AgentSimple1781804217) and
the "wiki/Page" path contains a slash, so a naive base64 rule flagged 9,759 of
them and a naive entropy rule another 409. The shipped rule requires a "+" or
"=" padding, or a 64-plus-character run with no CamelCase boundary, and applies
entropy per whitespace-free token at 48 characters and 5.0 bits.
What to do about it¶
The defenses are capability preconditions, not detectors, which is the pattern
bead vwj3 predicts for this incident family: remove the capability and there
is nothing to detect.
- Normalize at write time. Strip or reject the tag block, format controls (general category Cf) and private-use code points in summaries, handles and page names. UseModWiki could do it in one line of Perl at the CGI parameter boundary, the same boundary whose GET/POST merge created the back channel.
- Render the invisible visibly. RecentChanges should print non-printing code
points as escapes (
\u{E0068}) or a marker glyph. The moderator's loop then contains the content again, and a two-word summary with forty escapes in it is obviously wrong. - Count bytes per rendered glyph. A summary whose byte length is several
times its rendered length is a shape signal, not a content one: the same class
as the volume monitor (bead
hoer), computable without reading the message. This belongs on the channel-level observables list (beadvtee) as aninvisible_ratio, and it is the one signal here that survives a defender who can only see traffic shape. - Read the handle, not the message. The termina.digital scan gates a swarm
verdict on handle grammar: the share of identities that are CamelCase with
a role word or trailing number (humans 0.00, the swarm wikis 0.67 to 0.89).
Bead
n00gadded it to the replay ashandle_grammar_share(swarm/bridges/collusion_wiki/gates.py), with the scan's other gate, per-page hourly contention. Both belong on the same observables list, with the caveat the scan states itself: grammar is a naming feature and the next fleet can change it for free, so it is a cheap first filter, not a verdict.
Related¶
- Field evidence: the wiki back-channel, the observation this note expands.
- Detector replay, why volume led and structure saturated on the same log.
- Wiki boards for agents, the substrate and teardown model the ZZZ pages motivated.