ShrouDB
Store user files you can permanently delete

Stash

Encrypted file storage on S3 with cryptographic deletion.

Stash encrypts each file under its own key before writing it to S3 or an S3-compatible store such as MinIO or R2. REVOKE destroys that key, which makes the stored bytes unreadable everywhere they were copied, backups included.

Use it from your app

typescript
import { ShrouDB } from "@shroudb/sdk";

const db = new ShrouDB({
  moat: process.env.SHROUDB_URL,   // e.g. http://localhost:8200
  token: process.env.SHROUDB_TOKEN,
});

// Upload
await db.stash.store(fileId, bytes.toString("base64"), {
  content_type: "application/pdf",
});

// Download
const file = await db.stash.retrieve(fileId);

// The user asks to be deleted: revoke the key.
// The bytes in S3, and in any backup of them, are now unreadable.
await db.stash.revoke(fileId);

What it does

  • Each file gets its own data key, wrapped by a Cipher keyring.
  • Works with S3 and S3-compatible stores such as MinIO and R2.
  • REVOKE destroys the key, so every stored copy becomes unreadable.
  • INSPECT reads metadata without decrypting the file.
  • Per-viewer copies with FINGERPRINT and TRACE, to trace a leak to its source.

Turn it on

Stash runs inside Moat, the ShrouDB server. Add this to moat.tomland restart. It shares Moat's encrypted storage, access tokens, and audit log with the other engines.

moat.toml
[engines.stash]
enabled = true
bucket = "acme-user-files"
region = "us-east-1"
# endpoint = "https://<account>.r2.cloudflarestorage.com"  # for S3-compatible stores

Commands

Over RESP3, prefix each command with STASH. Over HTTP, send POST /v1/stash {"args": [...]}. The SDKs have a method for each.

CommandArgsDescription
STORE<id> <base64> [CONTENT_TYPE <type>]Encrypt and upload
RETRIEVE<id>Download and decrypt
INSPECT<id>Read metadata only
REVOKE<id> [SOFT]Destroy the file's key
REWRAP<id>Rewrap the file key under the current Cipher key
FINGERPRINT<id> <viewer_id>Create a traceable copy for one viewer
Try Stash locally
The quickstart takes about five minutes.