Secret
An ultra-simple, dependency free PHP app for sharing sensitive text (basically like onetimesecret), but with full end-to-end AES-256-GCM encryption so even the server has no access to the data, and developed with very simple deployment in mind.
Install / Use
/learn @alancwoo/SecretREADME
Secret
A minimal PHP app for sharing sensitive text and files (like onetimesecret), with full end-to-end AES-256-GCM encryption. The server never sees plaintext data as it is encrypted by a client-side key. Zero framework dependencies and incredibly simple to deploy.

What is it for
Send credentials or sensitive information to clients and colleagues without it sitting forever in email/chat threads prone to breaches.
Secrets are encrypted client-side, viewed once, then deleted. For increased security, send the URL and KEY separately through different channels.
Features
- End-to-end AES-256-GCM encryption (Web Crypto API)
- Text and file sharing (up to 10MB)
- Configurable expiry (5 minutes to 7 days, or unlimited)
- Configurable view limit (1, 3, 5, 10, or unlimited views)
- Request a secret — generate a one-time link for someone to send you a secret
- No framework, no Composer, no vendor directory
- SQLite database (auto-created)
- Deploy by uploading files to any PHP host
Requirements
- PHP 8.0+ with PDO SQLite extension
mod_rewrite(Apache) or equivalent URL rewriting- HTTPS with a proper certificate (required for Web Crypto API)
Install
- Clone or upload the repo
- Copy
.env.exampleto.env - Configure
NEW_ITEM_PASSWORD(recommended — see Why set a password?) - That's it. The SQLite database is created automatically on first request.
Deploy
Upload the whole project to your server. A root .htaccess redirects all requests into public/ automatically — no virtual host configuration needed. Works on any shared host with Apache and mod_rewrite.
If you can configure your web server's document root directly, point it at public/ for a cleaner setup.
No composer install. No npm install. No build step. No dependencies at all.
Customising
- Logo/header: Replace
public/images/header.pngwith your own image. - Colours, fonts, spacing: Edit the CSS custom properties at the top of
public/css/app.css. - Client-side logic: Edit
public/js/app.jsdirectly.
No build step required.
Routes
| Method | URL | Purpose |
|--------|-----|---------|
| GET | / | Create secret form |
| POST | /api/secret | Create a new secret (JSON) |
| GET | /s/{id} | View/decrypt secret page |
| GET | /api/secret/{id} | Fetch encrypted data (JSON) |
| DELETE | /api/secret/{id} | Delete a secret |
| POST | /api/request | Create a secret request (requires password) |
| GET | /r/{token} | Request form (for the recipient) |
| POST | /api/request/{token}/submit | Submit a secret via request token |
Why Set a Password?
- Without a password, anyone can create secrets
- There's no rate limiter, so a troll could hammer the endpoint
- There's no CSRF protection (irrelevant without a password since anyone can create secrets anyway)
- Sanitization is performed client-side before display (configured via
ALLOWED_TAGSenv var) since the server only sees encrypted data
Tests
php tests/run.php
Runs 111 tests covering the API, view counting, expiry, file uploads, secret requests, static assets, password protection, input validation, and error handling. Uses a temporary database — safe to run against a live install.
