A pastebin that ships a warning against exposing it
wastebin is a pastebin 📝
At a glance
- What is it?
- Wastebin is a small Rust pastebin on axum and sqlite3 that compresses with zstd, highlights more than 170 languages and encrypts with ChaCha20Poly1305. It also publishes an explicit list of what it does not do, and a caution telling you not to put it on the internet without a rate limiter in front.
- Who is it for?
- Judgment: wastebin is a good pastebin for a private network or a small team, and the documentation is more honest than most. Listing non-features, warning against public exposure, and naming the exact sqlite error caused by a missing TMPDIR are all things projects usually leave out.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly Rust, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 3, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The project lists what it does not do, then warns you about it
There is a Non-features section, and it is short and specific: no user authentication, no admin functionality, no arbitrary file uploads, and no mitigations for the various kinds of denial-of-service vector. A caution block then says the obvious consequence, that because of the missing authentication and further DoS mitigations it is not advised to run wastebin facing the internet as is, and that anyone who plans to anyway is strongly advised to rate limit inbound requests with iptables rules or a properly configured reverse proxy. So the security posture is not hidden, it is stated. What it means in practice is that pastebin is an application-level service with no accounts, no abuse handling and no capacity planning, sitting behind whatever you put in front of it. The demo instance at bin.bloerg.net is described as resetting every day, which is consistent with treating public exposure as something you engineer around.
Encryption without accounts, and three ways to delete a paste
Entries are encrypted with ChaCha20Poly1305, and passwords are hashed with argon2 rather than stored. There is no user table behind that, because authentication is a non-feature. What exists instead is ownership by token: a paste can be deleted after it expires, after it has been read, or by the anonymous owner who holds the secret. That is a different model from a pastebin with accounts, and it changes what you can expect. You cannot retrieve a paste you forgot the id of, you cannot see your own history unless the client keeps it, and nobody can recover a lost owner token for you. The compression story is the other half of the storage picture: pastes are compressed with zstd, and syntax highlighting for more than 170 languages comes from syntect, with nine colour themes in both light and dark mode shipped alongside. Markdown pastes are rendered to HTML, including GitHub-flavoured tables, task lists and admonitions.
The image is built FROM scratch, which is why migrations fail with 6410
The container image has no shell and no TMPDIR, and the documentation explains the consequence rather than leaving you to guess. The note says that if database migrations fail with an extended sqlite error code 6410, you should pass TMPDIR pointing at a location sqlite can write to. Both final stages of the Dockerfile are `FROM scratch`, which is where that comes from, and both copy just the passwd and group files so a non-root user can exist inside an image with no filesystem to speak of. The run recipe is correspondingly plain:
docker run \
-e WASTEBIN_DATABASE_PATH=/data/state.db \
-v /path/for/storage:/data \
-u $(id -u):$(id -g) \
quxfoo/wastebin:latestPassing your own uid and gid keeps the database file owned by you instead of by uid 10001. The compose example publishes 8088 and bind-mounts `./data`, and it carries the same instruction in prose: make sure that folder is writable by user 10001.
You cannot build an aarch64 image on an aarch64 host
The Dockerfile cross-compiles rather than emulating, using zig to link against musl. The builder is `rust:1.95`, it adds both musl targets with rustup, downloads a pinned zig 0.15.2, installs cargo-zigbuild, and then builds the server and the control tool for aarch64-unknown-linux-musl and x86_64-unknown-linux-musl in one pass. Two consequences are stated rather than discovered. The file is designed to be run from an x86_64 host, and the README is explicit that you cannot build aarch64 images on aarch64 hosts with it. The flag that selects the target is `--target`, with separate amd64 and arm64 builds under both Docker and Podman. The image tag in the examples is still `wastebin:v3.0.0`, three minor versions behind the 3.8.0 the manifest now declares, so anyone copying the command gets an older name than the example implies.
The build instructions say Rust 1.85 and the manifest requires 1.95
The build-from-source section says to install a Rust 2024 toolchain containing Rust 1.85 with rustup, then run the server with `cargo run --release`. The manifest disagrees on two counts: it sets `rust-version = "1.95"` and it sets `edition = "2024"`. The container builder image, rust:1.95, sides with the manifest, so the number in the README is the outlier rather than the manifest being aspirational. This matters because the two numbers describe different toolchains: the edition requirement is about language features and the rust-version field is the compiler floor that Cargo enforces, and a contributor following the README literally will install a toolchain the manifest refuses. The Nix path sidesteps the question, since a flake.nix and flake.lock are in the tree and `nix run 'github:matze/wastebin#wastebin'` pins whatever the flake was written against.
The README calls itself unreleased while 3.8.0 is both tag and version
The documentation opens with a banner saying you are reading the documentation for an unreleased version, followed by a list of released versions whose first entry is 3.8.0, linked to a specific commit tree. The manifest says version 3.8.0. The newest release is 3.8.0, published on 2 October 2026. Those four statements cannot all describe the same moment: either the checked-out documentation describes work newer than 3.8.0 while the manifest still reads 3.8.0, or the banner is a leftover from before the tag. The banner also lists ten released versions going back to 2.7.1, each pinned to a commit hash rather than a tag, which is a deliberate way to make older documentation addressable. The cadence underneath is irregular: 3.7.1 on 31 July, 3.7.2 on 10 August, then nothing until 3.8.0 on 2 October, with the last push to the repository on 26 September.
One route relaxes the content security policy, and the docs show it empty
Markdown handling has its own path, at `/md/{id}`, with a toggle between the highlighted source and the rendered output. Raw HTML inside the Markdown is run through the ammonia sanitiser, so safe structural tags such as details, summary and kbd survive while script elements, inline event handlers and `javascript:` URLs are stripped. One relaxation exists: to permit external images embedded in the Markdown, the content security policy is loosened to `img-src *`, and only for `/md/*` responses, with every other route keeping the strict default. That scoping is the right shape for the exception. The documentation of it has a small defect, though, because the sentence about permitting external images shows an empty code span where the tag should be, so the reader has to infer which element is being allowed. Fenced code blocks inside rendered Markdown are highlighted with the same theme as ordinary pastes.
Trimmed defaults, an rc dependency, and a wall of denied lints
The manifest shows how much was deliberately left out. syntect is declared with `default-features = false` and only html, plist-load and regex-fancy enabled, so the syntax engine does not drag in its default extras. tokio also goes in with defaults off. Two entries stand out: the font crate two-face is pinned at 0.5.0-rc1, a release candidate in a project shipping 3.8.0, and askama handles templating. The lint table is unusually strict, with `unsafe_code` forbidden workspace-wide and clippy denying panic, unwrap_used, print_stdout, similar_names, unicode_not_nfc and five cast lints, while missing_errors_doc is left allowed. Two profile settings are deliberate as well: argon2 is compiled at opt-level 3 in dev only, so password hashing does not dominate test runs, and release strips debuginfo with fat LTO. deny.toml and clippy.toml at the root support both practices.
Editorial conclusion
Judgment: wastebin is a good pastebin for a private network or a small team, and the documentation is more honest than most. Listing non-features, warning against public exposure, and naming the exact sqlite error caused by a missing TMPDIR are all things projects usually leave out. The version story needs one fix before anyone builds on it, though: the manifest and the container builder both require Rust 1.95 while the build-from-source section still says 1.85, and the README simultaneously describes itself as unreleased and lists 3.8.0 as the newest release, which is also the manifest version. Anyone running it should read the non-features list as a checklist rather than a footnote, put a reverse proxy in front as advised, keep the owner deletion path in mind since there are no accounts, and check the Markdown route separately if external images matter, because that is the one path with a relaxed content security policy.
Frequently asked questions
What is wastebin?
A minimal pastebin written in Rust on an axum and sqlite3 backend, shipped as a single binary. It compresses pastes with zstd, highlights more than 170 languages with syntect, renders Markdown to HTML, encrypts entries with ChaCha20Poly1305 and argon2 hashed passwords, and comes with nine colour themes in light and dark mode.
Is it safe to expose wastebin to the internet?
The project says not as is. Its non-features list excludes user authentication, admin functionality and mitigations for denial-of-service vectors, and the caution advises rate limiting inbound requests with iptables rules or a properly configured reverse proxy before doing so.
How do I run wastebin in Docker?
Pull quxfoo/wastebin:latest, set WASTEBIN_DATABASE_PATH and bind mount a storage directory, and run it as your own user with -u $(id -u):$(id -g) so the database stays yours. The image is based on scratch, so it has no shell and no TMPDIR; if migrations fail with extended sqlite error code 6410, point TMPDIR at a writable location.
How do you delete a paste in wastebin?
Three ways: after expiration, after it has been read, or by the anonymous owner holding the secret. There are no user accounts, since user authentication and admin functionality are listed as non-features, so a lost owner token means a lost paste.
Which Rust version does wastebin need?
The manifest sets rust-version to 1.95 with edition 2024, and the container builder image is rust:1.95. The build-from-source instructions in the README still say to install a toolchain containing Rust 1.85, which is the number that needs correcting.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/matze-wastebin)