# Conversation Stenography: hiding messages in LLM-generated chat text

> A Go command line tool that encrypts a message, then disguises the ciphertext inside ordinary-looking text produced by a local language model. It is a proof of concept, and the README says so itself.

**nethical6/conversation-steganography** — Use LLMs to hide messages inside normal looking conversations

- Repository: https://github.com/nethical6/conversation-steganography
- Stars: 1,250 · Forks: 91
- Language: Go
- License: GPL-3.0
- Published: 2026-09-10 · Updated: 2026-09-10 · Language: en
- Canonical page: https://hysenlabs.com/projects/nethical6-conversation-steganography

## The problem Conversation Stenography attacks

Ordinary encrypted chat has a metadata problem before it has a cryptography problem. A message that looks encrypted, or that arrives through a tool associated with encrypted messaging, is itself a signal. The README states the motivation plainly: governments are moving toward scanning private messages, and sending normal encrypted messages is risky because it might flag you on the basis of suspicion. The goal is not stronger encryption but a different shape of traffic. What leaves your device is text that reads like an everyday chat message, so the messaging platform only ever sees innocent cover text.

The intended user is not a security team. The README carries a personal note from the author, who describes himself as 18 and says the project simply demonstrates a practical use case for LLMs that may already be operating at scale. It also carries an explicit caution that the project is for educational and research purposes. Read that as the real scope: this is a working demonstration of an idea, shipped as a Go program you can build and run, not a product with a support policy.

## How the encrypt, encode, decode pipeline is wired

The README gives a diagram, and the repository layout backs it up. A secret message is encrypted with AES-SIV, an authenticated mode that also resists nonce reuse. The resulting bytes are not hidden in image pixels or whitespace. They are encoded into the token choices the language model makes while generating cover text, so the ciphertext lives in which plausible word the model picked at each position, not in the visible characters.

The repository files map onto that pipeline. codec.go and siv.go handle the encoding and the AES-SIV layer. generative.go and process_model.go sit on the model side. huffman.go and arithmetic.go are entropy coding, which is how a byte stream gets mapped onto a distribution of token choices. conversation_chain.go links each message to the previous one, and carrier_security.go is the piece that reasons about the cover text itself. The README lists the security properties it aims for: AES-SIV authenticated encryption, a conversation chain where tampering, deletion or reordering is detected, a model that runs entirely on your device, and a shared secret phrase derived with PBKDF2 at 600,000 rounds and never stored on disk.

That last property has a sharp consequence. There is no key file to back up and no password reset. If the phrase is lost, the conversation is gone. The README gives the shape of a good one: six or more random words, with "purple elephant dances under crimson moonlight" as its example.

## Build it and run the two-user simulation

The project is a Go module named conversationstenography, targeting Go 1.22, with golang.org/x/term as its only direct dependency. The README's install path is a clone and a build:

```bash
git clone https://github.com/nethical/conversation-stenography.git
cd conversation-stenography
go build -o conversation-stenography ./cmd/conversation-stenography
```

Running the binary with no arguments starts a setup wizard on first run. According to the README it lets you pick an AI model with recommendations for your system, downloads the model automatically, and creates your config file. The repository ships conversation-stenography.example.json, so the config shape is inspectable before you commit to a model choice.

You do not need two machines to see whether the protocol round-trips. The README provides a simulation mode:

```bash
./conversation-stenography simulate
```

It prompts for your shared secret phrase, then starts the terminal as Alice. You type a plaintext message, the tool generates cover text and immediately decodes it as Bob, and the prompt switches users. The README notes that each turn uses two independent protocol participants, one generating and one decoding, which exercises the same encryption, model encoding, decoding and conversation chain used between separate devices. Names and the conversation label are configurable:

```bash
./conversation-stenography simulate -user-a Alex -user-b Samir -conversation test-chat
```

Inside the simulation, /switch changes the active user without sending, /show prints the simulated plaintext conversation, /help lists the commands, and /quit exits without saving state. That last detail matters: the README says simulation state is not saved, so it is a smoke test, not a rehearsal you can resume.

## Sending a real message and pasting a reply

For actual use, both people need the exact same configuration. The README asks them to meet in person and agree on three things: a secret phrase, a conversation name such as coffee-plans, and the same model, for example both picking option 1 in the wizard. Each person then runs the binary, enters the same conversation name, their own name, and the shared phrase.

To send, you type your secret message at the prompt. The tool prints a block labelled as the text to copy into your messaging app. The README's own example takes a request to meet at a coffee shop and produces a cover message about a recipe and fresh basil. You copy that block into WhatsApp, Telegram, Signal, iMessage, email or Instagram DMs. Nothing else is sent.

Receiving is the part that breaks people's assumptions. You do not paste the arriving message as a normal chat line. You invoke the paste command and name the sender:

```text
alex> /paste bob
```

The tool then asks for the exact message received, and you terminate it with /end on its own line. It prints the decoded plaintext. The README is emphatic about ordering: both people must process messages in the exact same order they appear in the messaging app, and if you miss one you must use /paste to process it before sending your next reply. That is the conversation chain doing its job, and it is also the most likely way a real conversation stalls.

## Where this design fails, and who should not rely on it

The README does not oversell. It carries a warning that this is a proof of concept and still has multiple issues, and adds that several techniques are already being developed to determine whether a text has hidden content. Treat that as the headline limitation rather than a footnote. The entire premise is that cover text is indistinguishable from human chat. If a detector can score token-choice distributions, the premise weakens, and the author says as much.

Ordering is the second failure mode. The conversation chain detects tampering, deletion and reordering, which is good for integrity and bad for usability: a single message processed out of order, or skipped and never pasted, desynchronises the two sides. There is no documented resynchronisation path in the README. The README does not document rollback either, and the simulation explicitly does not persist state.

Model agreement is the third. Both sides must run the same model, and the setup wizard downloads it. If one person picks a different option, the token distributions differ and decoding fails. That is a hard constraint, not a preference, and it means the two participants need comparable local hardware and a working download of the same weights.

Finally, consider what the tool does not protect. It does not hide that you are running it, and it does not hide the fact that cover text was machine-generated if someone inspects it closely. It also assumes a shared secret exchanged out of band. If you cannot meet in person or use another channel to agree on the phrase, the README's own setup instructions do not apply to you.

## How it differs from encryption tools and from image steganography

The obvious alternative is just using Signal or another end-to-end encrypted messenger. The difference is in what an observer sees. Signal protects content and hides it behind an encrypted transport, but the traffic is recognisably Signal traffic. Conversation Stenography produces plain text that travels through whatever app you already use, including ones with no encryption story at all, and the carrier is the chat itself. The trade is real: you inherit the security of the carrier app for transport, and you inherit its ordering and delivery behaviour, which the conversation chain then depends on.

The closer comparison is classical steganography, hiding data in image pixels or audio samples. Those carriers are static: you embed once and the file is the message. Here the carrier is generated fresh for every message by a language model, and the payload lives in the sampling decisions rather than in bits of a file. That makes each cover text unique and avoids the reused-image tell, but it also makes correctness depend on both parties running identical model weights and identical decoding logic, a much stricter requirement than agreeing on a JPEG.

## Licence, maintenance and what an upgrade costs

The project is licensed GPL-3.0. For someone reading the source or running the binary locally, that is unremarkable. For anyone who wants to embed this in a closed product, the copyleft terms apply to distributed derivative works, and the README's educational-use framing sits alongside the licence rather than replacing it. That is a description of the licence text, not legal advice; if you plan to ship something, read the LICENSE file in the repository.

The repository is not archived, and the last push was on 2026-07-18. There are no retrieved releases, so there is no tagged version to pin and no changelog to read. Upgrades therefore mean pulling main and rebuilding. Two things make that cheaper than it sounds: the module has a single direct dependency, golang.org/x/term, and the test suite is spread across the core files, with codec_test.go, siv_test.go, conversation_chain_test.go, generative_test.go, huffman_test.go, message_compression_test.go, phrase_test.go, process_model_test.go and carrier_security_test.go all present in the repository root. Run go test ./... after a pull. The expensive part of any upgrade is not the Go code, it is the model: if the wizard's recommendations change, both participants have to move to the same new weights together, and any conversation in flight is stranded.

## Conclusion

Adopt it if you want to read the code behind LLM token-level steganography, or to reproduce the two-user simulation on one machine before trusting the idea. Do not adopt it for real operational secrecy: the README labels it a proof of concept with multiple issues and notes that detection techniques are already being developed. Verify first that both sides can run the same model locally, that your shared secret phrase is long and random, and that you can keep message order intact, because the conversation chain breaks on a missed message.

## FAQ

### How can hidden content in Conversation Stenography cover text be detected?

The README warns that several techniques are already being developed to determine whether a text has hidden content, and that this project is a proof of concept with multiple issues. It does not describe a specific detector or claim resistance to one.

### Can you give an example of how Conversation Stenography hides a message?

The README's example takes the secret message "meet me at the coffee shop at 3pm" and generates cover text about a recipe and fresh basil, which is what actually gets sent in the chat app. The recipient's copy of the tool decodes it back to the original sentence.

### Do hackers use steganography like Conversation Stenography?

The README does not address who uses steganography in practice. It states only that the project is provided for educational and research purposes and that unauthorized or illegal activities are prohibited.

### Is Conversation Stenography used to hide messages?

Yes, that is its stated purpose: it encrypts a message with AES-SIV and disguises it as natural-sounding text generated by a local model, so the messaging platform only sees the cover text. Both participants need the same model, the same conversation name and the same shared secret phrase.

## Sources

- [Issues](https://github.com/nethical6/conversation-steganography/issues)
- [License: GPL-3.0](https://github.com/nethical6/conversation-steganography/blob/main/LICENSE)
- [nethical6/conversation-steganography on GitHub](https://github.com/nethical6/conversation-steganography)
- [README](https://github.com/nethical6/conversation-steganography/blob/main/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/nethical6-conversation-steganography
