Why MicroBin's Uploader Password Silently Does Nothing (And How to Fix It)

Introduction

We run a self-hosted content and automation platform built on Docker Compose — n8n, NocoDB, Caddy, Ghost, and a handful of other services all living on a single VPS. One of the quieter but surprisingly useful pieces of the stack is MicroBin — a lightweight, self-hosted paste tool written in Rust.

We use it constantly: sharing Caddyfiles with ourselves across sessions, passing config snippets to automation workflows, and letting AI tools fetch raw text via direct URLs. It's simple, fast, and self-contained.

But when we tried to lock it down so only we could create pastes, we ran into a frustrating silent failure. The MICROBIN_UPLOADER_PASSWORD environment variable was set, the admin panel confirmed it was "set" — and yet anyone could save a paste without entering a password at all.

This post documents the investigation and the fix.


The Problem

The goal was simple: restrict paste creation to authorized users only, while keeping pastes publicly readable via direct URL (so automation tools and AI assistants could still fetch content).

MicroBin supports an MICROBIN_UPLOADER_PASSWORD environment variable for exactly this purpose. We set it in our Docker Compose config:

yaml

environment:
  - MICROBIN_UPLOADER_PASSWORD=your-password-here
  - MICROBIN_PRIVATE=true
  - MICROBIN_NO_LISTING=true

We restarted the container, visited the paste UI — and saw no password field anywhere. Confused, we tried saving a paste anyway. It saved. No prompt, no rejection, nothing.

The MicroBin admin panel at /admin showed:

uploader_password    set

So the variable was being read. But it wasn't being enforced.


First Attempts (What Didn't Work)

Checking the environment variables directly:

bash

docker inspect microbin | grep -A 50 "Env"

The password was definitely there. The container was reading it correctly.

Checking the MicroBin version:

We were running danielszabo99/microbin:latest which resolved to v2.1.4. No obvious changelog entries about uploader password being broken.

Restarting the container:

Tried a full docker compose down && docker compose up -d microbin. Same result — no password field, pastes saved freely.

Trying a private browser window:

Thought maybe the browser had cached an authenticated session. Opened a fresh private window, navigated to the paste UI — still no uploader password field visible anywhere on the page.

None of this helped. The feature appeared to be simply non-functional.


Investigation

We dug into the MicroBin logs to see what was actually happening server-side when a paste was submitted:

bash

docker logs microbin --tail 30

When we deliberately entered a wrong password (after finally getting the field to appear — more on that below), the log showed:

[WARN] - Uploader password mismatch. Input length: 20, Expected length: 18

So the backend was validating the password — it just wasn't showing the input field in the UI under our current configuration.

This pointed to a frontend rendering condition, not a backend bug. The password was being checked, but the field to enter it was being hidden.

We started looking at which environment variables might control the visibility of the uploader password field. The admin panel gave us a full dump of active settings:

readonly        false
enable_readonly true
private         true
no_listing      true
uploader_password  set

The key clue was readonly: false alongside enable_readonly: true. MicroBin has a concept of a "readonly mode" where the site defaults to read-only and users must supply the uploader password to bypass it. The uploader password field is part of that readonly bypass flow — not a standalone feature.


The Root Cause

MICROBIN_UPLOADER_PASSWORD in MicroBin is not a standalone access gate. It is specifically the bypass password for readonly mode.

When MICROBIN_READONLY=false (the default), the site is open for anyone to submit pastes, and the uploader password UI is never shown — because there's nothing to bypass.

The uploader password field only appears in the UI when:

  • MICROBIN_ENABLE_READONLY=true — enables the readonly mode feature
  • MICROBIN_READONLY=true — sets the site to readonly by default

Without both of these flags, MICROBIN_UPLOADER_PASSWORD is read by the backend but the frontend never presents the input field, making the feature invisible and effectively non-functional from the user's perspective.

This is a confusing design — the variable name implies it's an independent upload gate, but it only works as part of the readonly subsystem.


The Fix

Add both readonly flags to your MicroBin service in docker-compose.yml:

yaml

microbin:
  image: danielszabo99/microbin:latest
  container_name: microbin
  restart: unless-stopped
  volumes:
    - /root/microbin-data:/app/pasta_data
  environment:
    - MICROBIN_UPLOADER_PASSWORD=your-secure-password
    - MICROBIN_ENABLE_READONLY=true      # enables the readonly feature
    - MICROBIN_READONLY=true             # sets site to readonly by default
    - MICROBIN_PRIVATE=true
    - MICROBIN_NO_LISTING=true
    - MICROBIN_GC_DAYS=0                 # delete expired pastes immediately
    - MICROBIN_PUBLIC_PATH=https://paste.[DOMAIN]
    - MICROBIN_HIGHLIGHTSYNTAX=true
    - MICROBIN_DEFAULT_EXPIRY=1hour
    - MICROBIN_MAX_EXPIRY=24hour
    - MICROBIN_NO_FILE_UPLOAD=true

Then restart the service:

bash

docker compose up -d microbin

Verification

After restarting with the new config, the paste UI now shows an Uploader Password field next to the Save button. Submitting without a password redirects to /incorrect. Submitting with the correct password saves the paste successfully.

The logs confirm correct behavior:

[WARN] - Uploader password mismatch. Input length: X, Expected length: Y
[INFO] - POST /upload → 302 /incorrect

And with the correct password:

[INFO] - POST /upload → 302 /upload/slug-name-here

Public read access via direct URL still works without any password — which is exactly what we needed for automation tools and external fetch calls.


Bonus: The Password Length Trap

One more gotcha worth mentioning. After enabling the field, we copy-pasted the password from our config — and still got rejected. The logs showed:

Uploader password mismatch. Input length: 20, Expected length: 18

We were typing 20 characters when the actual password was 18. The culprit: invisible leading or trailing spaces picked up during copy-paste. MicroBin does exact string matching with no trimming.

Always type your uploader password manually the first time, or make sure your password manager isn't adding whitespace on paste.


Key Lessons

1. MICROBIN_UPLOADER_PASSWORD only works with readonly mode enabled. Without MICROBIN_ENABLE_READONLY=true and MICROBIN_READONLY=true, the variable is read but the UI never shows the input field.

2. The admin panel saying "set" doesn't mean the feature is active. It just means the environment variable was parsed. Functional enforcement is a separate concern.

3. Always check logs when a security feature appears to do nothing. The docker logs output immediately showed the backend was validating — which told us the problem was in the UI layer, not the backend.

4. Watch for whitespace in pasted passwords. MicroBin does exact matching. A space character will silently cause every login attempt to fail with a misleading length mismatch warning.

5. Add a persistent volume. By default, a MicroBin container started without a volume bind stores all paste data inside the container. A restart wipes everything. Always mount /app/pasta_data to a host path.

Subscribe to The Chimp Talks

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe