Skip to content
VoidNote

Stop pasting secrets in Slack

Every team does it. Everyone knows it's wrong. Here's a pattern that actually fixes it — without changing your workflow.

There's a message in your Slack history right now that looks something like this:

@alice here's the prod DB password: Kx9#mR2$vLp...

— sent 14 months ago, #engineering, 3 people copied it to notes

You've done it. I've done it. Everyone's done it, because the alternative — setting up a secrets manager, getting everyone on 1Password, configuring Vault, explaining how to use it to your contractor — takes forty minutes and the DB migration is happening right now.

So the secret goes into Slack. And then it lives there. Forever.

It's worse than you think

The obvious problem: Slack messages don't expire. That password from 14 months ago is still there, searchable by every current and future team member with channel access. If you ever export your workspace — for compliance, for a legal hold, for an acquisition — that secret is in the archive.

The less obvious problem: Slack has integrations. Your workspace probably pushes messages into a logging service, a compliance tool, maybe a support platform. The secret you sent to one person potentially landed in three different third-party databases you forgot about.

The worst problem: you can't revoke it. Even if you delete the message, it was already ingested by the logging service. Even if you rotate the credential, you don't know who copied it. There's no audit trail. It just quietly exists in the dark.

Email is the same story. More persistent, wider blast radius, worse search discoverability (which means better attacker discoverability). "Can you forward me the creds?" threads forwarded to five more people, all of whom work with their inboxes synced to their phones.

Why the right solutions don't stick

HashiCorp Vault is excellent. 1Password Teams is excellent. AWS Secrets Manager, GCP Secret Manager, Infisical, Doppler — all excellent. None of them help with the situation described above, because the situation is human, not technical.

You need to give one specific secret to one specific person, right now, through a channel you're already in. The barrier to doing it safely has to be lower than the barrier to doing it unsafely, or people will always take the shortcut. They're not lazy — they're just trying to get work done.

The only fix that works in practice is a tool that's as fast as paste, works anywhere a link works, and leaves nothing behind.

A link that forgets itself

VoidNote is that tool. You create a note. You get a link. The recipient opens the link, the note is revealed, then it's gone. The entire flow takes fifteen seconds. The link works in Slack, email, SMS, a GitHub comment — anywhere you'd paste a secret today.

The cryptographic model matters here. Your browser generates a 64-character token and splits it in half:

fullToken = a1b2c3d4...e5f6a7b8... // 64 chars total

tokenId = a1b2c3d4... // first 32 — sent to server as lookup key

secret = e5f6a7b8... // last 32 — lives only in the URL

The content is encrypted with AES-256-GCM using a key derived from the secret half only — before it ever leaves your browser. The server receives an encrypted blob and a lookup token. It has no decryption key. It cannot read your note.

The recipient opens the link. The secret half is in the URL fragment. Their browser downloads the encrypted blob, decrypts it locally, shows the content, increments the view counter. When the view limit is hit, the blob is deleted. The key was never on the server. There's nothing left to breach.

From anywhere to anywhere

The web interface is the easiest path. But VoidNote is also infrastructure you can call from code.

The simplest example: you're on your phone, you need to get a secret to your laptop without emailing it to yourself:

# On your phone — create the note, get the link

curl -s https://voidnote.net/api/notes \

-H "Authorization: Bearer $VN_KEY" \

-H "Content-Type: application/json" \

-d '{"content":"my-secret","maxViews":1}'

# On your laptop — consume it, pipe wherever

curl -s https://voidnote.net/api/note/<token> | jq -r .content

Or install the CLI helper: voidnote <link> reads the note, sends content to stdout, metadata to stderr, and it's gone. One view, one read, nothing left.

The pipeable design is intentional. Content goes to stdout, status goes to stderr, so you can:

voidnote https://voidnote.net/note/abc123... | pbcopy

voidnote https://voidnote.net/note/abc123... > ~/.ssh/id_rsa

voidnote https://voidnote.net/note/abc123... | docker login --password-stdin

CI/CD pipelines and AI agents

The same problem shows up in automated systems. You need to pass a credential to a CI job, a deployment script, or an AI agent — but you don't want it sitting in an environment variable that outlives the task, or in a config file that ends up in a log.

# In your CI pipeline

- name: Deploy

run: |

# Secret injected once, consumed, gone

DEPLOY_KEY=$(voidnote ${{ secrets.DEPLOY_NOTE_URL }})

./deploy.sh --key "$DEPLOY_KEY"

For AI agents, this pattern becomes more powerful. You can give an agent a VoidNote URL instead of a raw credential. The agent consumes it exactly once to do its job — and now you have a cryptographic audit trail: the note was viewed once, at a specific time, from a specific IP. If the note was already consumed when the agent tries to read it, something went wrong in the pipeline.

The SDK makes this three lines in any language:

# Python

import voidnote

result = voidnote.read("https://voidnote.net/note/abc123...")

deploy(api_key=result.content) # result.destroyed is True after this

Live secrets with Void Stream

Some workflows need more than a one-shot note. You want to stream a deployment log, pipe a build output across machines, or send structured credentials to an agent in real time — without any of it persisting after the session ends.

Void Stream is an encrypted real-time channel. One writer, one or many readers, end-to-end encrypted the same way notes are — the server routes ciphertext it cannot read. The channel self-destructs when the writer closes it or the session expires.

# Writer — pipe any output into a live encrypted stream

./build.sh 2>&1 | voidnote stream write

→ https://voidnote.net/stream/a1b2c3d4...

# Reader — follow the stream live, nothing stored

voidnote stream read https://voidnote.net/stream/a1b2c3d4...

The same model as notes: the decryption key lives only in the URL fragment, the server never touches plaintext. Useful wherever you'd otherwise use a shared terminal session, a Slack call, or a temporary paste — but want the ephemeral guarantee built in.

The SDK exposes the same interface in every language. Create a stream, get a URL, write to it, watch it from any reader. When you're done, close it. The channel disappears.

# TypeScript

import { VoidNote } from "voidnote"

const stream = await VoidNote.createStream(apiKey)

await stream.write("deploying v2.3.1...")

await stream.write(JSON.stringify(credentials))

await stream.close() // channel gone

The mental model that matters

The useful shift isn't "use a secrets manager." It's learning to think of secrets as things that should have a natural lifespan.

A credential you send to a contractor for a one-time task shouldn't exist six months later. An onboarding password shouldn't be recoverable after the new hire's first login. A deployment key passed through a CI job shouldn't survive the job.

Right now, secrets default to permanent unless you actively delete them from every place they landed. Slack messages, email threads, copy-paste buffers, browser history, terminal history — they accumulate silently. The rot is invisible until it isn't.

VoidNote flips the default. Secrets are ephemeral unless you explicitly make them persistent. The link expires. The note is destroyed. Nothing accumulates. There's nothing to breach because there's nothing left.

The practical part

Register at voidnote.net/register. You get 5 free notes on signup — enough to feel the flow before deciding it's useful. No credit card. Optional email.

Install the SDKs if you want to use it from code:

# JavaScript / TypeScript

npm install voidnote

# Python

pip install voidnote

# Go

go get github.com/quantum-encoding/voidnote-go

# Rust

cargo add voidnote

# Zig

zig fetch --save git+https://github.com/quantum-encoding/voidnote-zig

# Java / Kotlin (Gradle)

implementation("net.voidnote:voidnote-java:0.1.0")

# CLI (macOS / Linux)

brew install quantum-encoding/tap/voidnote

The technical architecture is documented at voidnote.net/how-it-works if you want to verify the zero-knowledge claims before trusting us with anything real.

The next time you're about to paste a credential into Slack — try the link instead. Fifteen seconds. No persistence. Nothing to clean up later.

Try it now

5 free notes on signup. No credit card. Works from a browser, the terminal, or your code.