Designed to vanish
A secure, open-source one-time secret sharing platform built with modern web technologies.
Features • Quick Start • Documentation • Contributing • License
Vanisec provides a production-grade, open-source solution for ephemeral secret sharing. Exchange sensitive data including passwords, API keys, authentication credentials, or confidential information via encrypted links designed for single-use access with automatic deletion.
- 🔒 Zero-Knowledge: Secrets are encrypted in your browser; the server only ever stores ciphertext, deleted immediately after access
- ⚡ Zero Friction: No registration, authentication, or account management required
- 🚀 Enterprise-Grade: Production-optimized container builds with comprehensive Kubernetes support
- 🎨 Polished Interface: Modern, responsive design featuring CloudDrove's visual identity
- 📦 Self-Hostable: Complete infrastructure control and data sovereignty
- 🌐 Open Source: MIT-licensed with active community participation
- One-Time Access: Secrets can only be viewed once and are immediately deleted after viewing
- Password Protection: Every secret is protected by a password that never leaves your browser — it derives the encryption key (PBKDF2) and gates retrieval via a one-way verifier
- Configurable Expiration: Set expiration times from 1 hour to 7 days (default: 24 hours)
- Automatic Cleanup: Redis TTL ensures expired secrets are automatically removed
- Unique URLs: Cryptographically secure, unguessable secret identifiers
- Clipboard: Paste text or a file at
/clipboard, get a four digit code (or scan the QR), and open it on any other device. Five minutes, one use, no login. Convenience rather than privacy: a four digit code is guessable and the key is held server side, so use one-time links for anything sensitive - Pairing Codes: Hand a secret to your own phone by typing a short code at
/cinstead of retyping a URL. Codes last five minutes, work once, and still require the password
- Modern Stack: Built with Next.js 16, TypeScript, and Tailwind CSS
- Containerized: Optimized multi-stage Docker builds with BuildKit caching
- Kubernetes Ready: Production-ready Helm charts included
- CI/CD: Automated builds and deployments via GitHub Actions
- Type Safe: Full TypeScript coverage for reliability
- SEO Optimized: Comprehensive metadata, structured data, and sitemap generation
- Zero-Knowledge Storage: Secrets are AES-GCM encrypted in the browser before upload; the server and Redis only ever hold ciphertext — never plaintext, filenames, or passwords
- No Persistence: Secrets are never logged or stored permanently
- Automatic Deletion: Immediate removal after viewing or expiration
- Non-Root Execution: Docker containers run with minimal privileges
- Health Monitoring: Built-in health checks and monitoring
- Quick Start
- Use it from your AI client
- Architecture
- Configuration
- Development
- Deployment
- Contributing
- Security
- License
The fastest way to get started with Vanisec:
# Enable BuildKit for faster builds (optional but recommended)
export DOCKER_BUILDKIT=1
export COMPOSE_DOCKER_CLI_BUILD=1
# Build and start services
docker-compose up -d --build
# View logs
docker-compose logs -f appThe application will be available at http://localhost:3000.
Common Commands:
# Stop services
docker-compose down
# View logs
docker-compose logs -f app
docker-compose logs -f redis
# Rebuild after changes
docker-compose up -d --build
# Remove volumes (clears Redis data)
docker-compose down -v- Node.js: 20.x or higher
- Redis: 7.x or higher (or use Docker for Redis only)
# Clone the repository
git clone https://github.com/clouddrove/vanisec.git
cd vanisec
# Install dependencies
npm install
# Start Redis (if not using Docker)
docker run -d -p 6379:6379 redis:7-alpine
# Or install Redis locally
redis-serverCreate a .env.local file:
REDIS_URL=redis://localhost:6379/3
NEXT_PUBLIC_BASE_URL=http://localhost:3000
GA_ID=G-XXXXXXXXXX # Optional: Google Analytics (runtime)npm run devOpen http://localhost:3000 in your browser.
npm run build
npm startVanisec includes production-ready Helm charts for Kubernetes deployment.
- Kubernetes cluster (1.19+)
- Helm 3.x
- kubectl configured
# Install with default values
helm install vanisec ./_infra/helm/vanisec
# Or install with custom values
helm install vanisec ./_infra/helm/vanisec -f my-values.yaml
# Upgrade existing installation
helm upgrade vanisec ./_infra/helm/vanisecEdit _infra/helm/vanisec/values.yaml to customize:
- Replica count and autoscaling
- Image repository and tag
- Resource limits and requests
- Redis configuration (embedded or external)
- Ingress settings and TLS
- Environment variables
Vanisec supports two Redis deployment modes:
Option 1: Embedded Redis (Default)
Redis is deployed as part of the Helm chart:
redis:
enabled: true # Deploy Redis with the application
password: "" # Optional: Set password for Redis authentication
persistence:
enabled: true
size: 8Gi
env:
REDIS_URL: "redis://vanisec-redis:6379/3" # Points to embedded Redis
REDIS_PASSWORD: "" # Optional: Redis passwordOption 2: External Redis
Use an existing Redis instance (managed service, external cluster, etc.):
redis:
enabled: false # Disable embedded Redis deployment
env:
# Point to your external Redis instance
REDIS_URL: "redis://external-redis.example.com:6379/3"
# Or with password:
# REDIS_URL: "redis://:password@external-redis.example.com:6379/3"
# Or using Kubernetes service:
# REDIS_URL: "redis://redis-service.namespace.svc.cluster.local:6379/3"
REDIS_PASSWORD: "" # Optional: Set if not included in URLExample: Using External Redis in Kubernetes
redis:
enabled: false # Don't deploy Redis
env:
# Connect to Redis in another namespace
REDIS_URL: "redis://redis.default.svc.cluster.local:6379/3"
REDIS_PASSWORD: "your-redis-password"Example: Using Managed Redis Service (AWS ElastiCache, Azure Cache, etc.)
redis:
enabled: false
env:
# Connect to managed Redis service
REDIS_URL: "redis://your-redis-cluster.cache.amazonaws.com:6379/3"
REDIS_PASSWORD: "your-secure-password"replicaCount: 3
image:
repository: ghcr.io/clouddrove/vanisec
tag: "latest"
redis:
enabled: true
password: "secure-redis-password"
persistence:
enabled: true
size: 8Gi
ingress:
enabled: true
className: "nginx"
hosts:
- host: vanisec.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: vanisec-tls
hosts:
- vanisec.example.com
autoscaling:
enabled: true
minReplicas: 2
maxReplicas: 10
targetCPUUtilizationPercentage: 80
env:
NEXT_PUBLIC_BASE_URL: "https://vanisec.example.com"
REDIS_URL: "redis://vanisec-redis:6379/3"
REDIS_PASSWORD: "secure-redis-password"Handing a credential to someone while working in an AI client usually means pasting it into the conversation, where the transcript keeps it. Vanisec ships an MCP server so you can create a one-time link instead, and a set of rules that tell the model which of the two tools to reach for.
claude mcp add vanisec -- npx -y @clouddrove/vanisec-mcpTwo tools. vanisec_generate_secret creates the value on your own machine and
puts the link password on your clipboard, so neither ever enters the
conversation. vanisec_create_secret takes a secret you already have, which
means both it and the password stay in the transcript. Prefer the first wherever
the secret does not exist yet.
There is deliberately no retrieval tool. A retrieved secret would land in the transcript, and a one-time secret would stop being one-time in any useful sense.
Requires Node 22 or newer. A hosted endpoint is also available at
/api/mcp for clients that can only use remote servers, but it encrypts server
side and is not zero-knowledge, so it is a fallback rather than the default.
Install instructions for Cursor, VS Code with Copilot, the Copilot CLI and cloud agent, Codex, Windsurf, Zed and the JetBrains family are in mcp/README.md. The top-level configuration key differs between clients and a wrong one fails silently, so use the block for your client rather than adapting another.
The guidance lives in skills/ as Agent Skills, which Claude Code,
Cursor and Codex all load, since they share the same SKILL.md format.
For clients that read something else, integrations/ carries the
same rules as Cursor rules, GitHub Copilot instructions and prompt files, and
AGENTS.md. Those files are meant to be copied into your own repository. They
are not applied to Vanisec itself.
/plugin marketplace add clouddrove/vanisec
/plugin install vanisec@vanisec
That installs the MCP server and the skills together in Claude Code.
Browse it all at vanisec.clouddrove.com/integrations.
┌─────────────┐
│ Client │
│ (Browser) │
└──────┬──────┘
│ HTTPS
▼
┌─────────────────────────────────┐
│ Next.js Application │
│ ┌───────────────────────────┐ │
│ │ API Routes │ │
│ │ - /api/secrets │ │
│ │ - /api/secrets/[id] │ │
│ │ - /api/pair │ │
│ │ - /api/pair/redeem │ │
│ │ - /api/clip │ │
│ │ - /api/clip/open │ │
│ └───────────────────────────┘ │
│ ┌───────────────────────────┐ │
│ │ Secret Management │ │
│ │ - Encryption │ │
│ │ - UUID Generation │ │
│ │ - TTL Management │ │
│ └───────────────────────────┘ │
└───────────┬─────────────────────┘
│
│ Redis Protocol
▼
┌─────────────────────────┐
│ Redis (Database 3) │
│ ┌───────────────────┐ │
│ │ Secret Storage │ │
│ │ - Encrypted Data │ │
│ │ - TTL Expiration │ │
│ │ - Auto Cleanup │ │
│ └───────────────────┘ │
└─────────────────────────┘
- Secret Creation: Secret encrypted in the browser (AES-GCM) → ciphertext uploaded → Stored in Redis with TTL → Unique URL generated
- Secret Access: URL accessed → password verifier checked → ciphertext atomically fetched-and-deleted (GETDEL) → decrypted in the browser → displayed once
- Expiration: Redis TTL expires → Secret automatically removed
| Component | Technology | Version |
|---|---|---|
| Framework | Next.js | 16.1+ |
| Language | TypeScript | 5.2+ |
| Styling | Tailwind CSS | 3.3+ |
| Database | Redis | 7.x |
| Container | Docker | Latest |
| Orchestration | Kubernetes + Helm | 1.19+ |
| Variable | Description | Default | Required |
|---|---|---|---|
REDIS_URL |
Redis connection URL | redis://localhost:6379/3 |
Yes |
REDIS_PASSWORD |
Redis password (if authentication enabled) | - | No |
REDIS_DB |
Redis database index. Ignored when REDIS_URL already selects one |
3 |
No |
TRUSTED_PROXY_HOPS |
Number of reverse proxies in front of the app. See below | 1 |
No |
NEXT_PUBLIC_BASE_URL |
Base URL for the application | https://vanisec.clouddrove.com |
No |
GA_ID |
Google Analytics Measurement ID (runtime; no rebuild needed) | - | No |
NEXT_PUBLIC_GA_ID |
Google Analytics Measurement ID (build-time alternative) | - | No |
NODE_ENV |
Environment mode | production |
No |
TRUSTED_PROXY_HOPS — set this to match your deployment.
Rate limiting identifies clients by IP, read from X-Forwarded-For. Each proxy
appends to that header, so only the rightmost entries are trustworthy; anything
further left was supplied by the caller and can be forged. The app reads the
Nth entry from the right, where N is TRUSTED_PROXY_HOPS.
| Deployment | Value |
|---|---|
| Single ingress / load balancer (default) | 1 |
| CDN in front of an ingress (e.g. Cloudflare → nginx) | 2 |
| No proxy, app exposed directly | 1 |
Setting it too high reads an entry the client controls, letting one caller forge unlimited identities and bypass rate limiting. Setting it too low buckets everyone behind the proxy together, so one noisy client can rate-limit everyone else. Count your actual hops.
Redis URL Format:
redis://[password@]host:port[/database]
redis://localhost:6379/3
redis://:password@redis.example.com:6379/3
The docker-compose.yml includes:
- Redis: Persistent storage with AOF enabled
- App: Production-optimized Next.js build
- Networks: Isolated Docker network
- Health Checks: Automatic container health monitoring
- Restart Policies: Automatic restart on failure
Key configuration options in _infra/helm/vanisec/values.yaml:
- Replicas: Number of application instances
- Resources: CPU and memory limits
- Redis:
redis.enabled: true- Deploy embedded Redis (default)redis.enabled: false- Use external Redis (setREDIS_URLaccordingly)
- Ingress: TLS termination and routing
- Autoscaling: Horizontal Pod Autoscaler settings
- Secrets: source sensitive values from a Kubernetes Secret rather than
plain Deployment env, either one the chart creates or one you already manage:
secrets.create: truewithsecrets.data.REDIS_PASSWORDrenders a Secret from your values. The value still passes through the values file andhelm get values, so this keeps it out of the Deployment spec and out of a GitOps repo, not out of Helm.secrets.existingSecret: my-secretreferences a Secret you manage yourself, which is the option to use if the value must never reach Helm at all.- The two are mutually exclusive, and a value is never rendered in both a Secret and plain env. Conflicting configuration fails the render rather than quietly picking one.
- The embedded Redis reads the same Secret, so it stays password protected.
TRUSTED_PROXY_HOPS: set it throughenv.TRUSTED_PROXY_HOPSto match the number of proxies that append toX-Forwarded-Forin front of the app. Too high is the dangerous direction: it selects an entry the caller supplied, so rate limiting can be bypassed. Too low only makes clients share a bucket.
Redis Deployment Modes:
-
Embedded Redis (
redis.enabled: true): Redis is deployed as part of the Helm release- Suitable for: Development, small deployments, single-tenant
- Benefits: Simple setup, no external dependencies
-
External Redis (
redis.enabled: false): Connect to existing Redis instance- Suitable for: Production, high availability, managed services
- Benefits: Better performance, shared infrastructure, managed backups
- In-app: Run the app and visit
/docs,/api,/faqfor usage and API details - Contributing: CONTRIBUTING.md
- Changelog: CHANGELOG.md
vanisec/
├── app/ # Next.js App Router
│ ├── api/ # API routes
│ ├── secret/ # Secret viewing pages
│ └── layout.tsx # Root layout
├── components/ # React components
│ ├── SecretForm.tsx # Secret creation form
│ ├── Header.tsx # Navigation header
│ └── Footer.tsx # Site footer
├── lib/ # Utility libraries
│ ├── redis.ts # Redis client
│ ├── rateLimit.ts # Client IP resolution and rate limiting
│ └── secrets.ts # Secret management
├── proxy.ts # Nonce-based CSP for /secret (Next 16 proxy convention)
├── test/ # Root test suite
│ └── integration/ # Tests needing a real Redis, excluded by default
├── mcp/ # @clouddrove/vanisec-mcp, published separately
├── skills/ # Agent Skills for AI clients
├── integrations/ # The same rules for Cursor, Copilot and AGENTS.md
├── _infra/ # Infrastructure as Code
│ └── helm/ # Kubernetes Helm charts
│ └── vanisec/ # Helm chart
├── .github/ # GitHub Actions workflows
│ └── workflows/ # CI/CD pipelines
└── public/ # Static assets
# Development server
npm run dev
# Production build
npm run build
# Start production server
npm start
# Linting
npm run lint
# Tests
npm test- TypeScript: Strict mode enabled
- ESLint: Next.js recommended rules
- Formatting: Prettier (via ESLint)
- Imports: Absolute imports with
@/prefix
# Root suite: API routes, rate limiting, the hosted MCP endpoint
npm test
# The published MCP package, which builds and tests on its own
cd mcp && npm testThe root suite needs no Redis. ioredis is redirected to an in-memory stand-in
through a module resolve hook, so lib/redis.ts, lib/rateLimit.ts and
lib/secrets.ts run unmodified.
Tests that genuinely need a real Redis live in test/integration/ and are
excluded from npm test, since they require Docker:
npm run test:integrationmcp/ is published to npm on its own and its CI job installs only that
directory, so nothing under mcp/ may import from the app. To check that still
holds, copy the repository somewhere with no node_modules, run npm ci inside
mcp/ alone, then npm run typecheck and npm test there.
Images are automatically built and pushed to GitHub Container Registry:
# Pull latest image
docker pull ghcr.io/clouddrove/vanisec:latest
# Pull specific version
docker pull ghcr.io/clouddrove/vanisec:06b08d1GitHub Actions workflows:
- Build and Push: Automatic Docker builds on push to
master - Dependabot: Automated dependency updates
- Auto-Merge: Automatic PR merging when CI passes
- Set
NEXT_PUBLIC_BASE_URLto your domain - Configure Redis password authentication
- Enable TLS/HTTPS via ingress or reverse proxy
- Set appropriate resource limits
- Configure monitoring and alerting
- Review security settings
- Set up backup strategy for Redis (if needed)
Contributions are essential for Vanisec's growth. See our Contributing Guide for complete details.
- Fork the repository to your account
- Create a feature branch:
git checkout -b feature/your-feature-name - Implement your changes
- Run validation:
npm run lint && npm test && npm run build - Commit with descriptive messages:
git commit -m 'feat: Add new feature' - Push to your fork:
git push origin feature/your-feature-name - Submit a pull request with a clear description
- Maintain TypeScript type safety and best practices
- Use conventional commit message format
- Update relevant documentation alongside code changes
- Include appropriate tests for new functionality
- Verify all linting and build checks pass before submitting
Security is a top priority for Vanisec. To report a security vulnerability:
- Do not create a public GitHub issue
- Send details via email to: security@clouddrove.com
- Provide detailed steps to reproduce the issue
- Include potential impact assessment if possible
- Expect a response within 48 hours acknowledging receipt
- Encryption: Secrets are AES-GCM encrypted in the browser; the server stores only ciphertext (zero-knowledge), atomically deleted on first view
- No Logging: Secrets are never logged or persisted
- Automatic Deletion: Immediate removal after viewing
- TTL Expiration: Automatic cleanup of expired secrets
- Non-Root Execution: Containers run with minimal privileges
- Input Validation: All inputs are validated and sanitized
- Use HTTPS in production
- Enable Redis password authentication
- Regularly update dependencies
- Monitor for security advisories
- Review access logs regularly
This project is licensed under the MIT License - see the LICENSE file for details.
Vanisec leverages several excellent open-source technologies:
- Next.js - React framework powering the application
- Tailwind CSS - Utility-first CSS framework for styling
- Redis - In-memory data store for ephemeral secret storage
- GitHub Container Registry - Container image hosting and distribution
- Documentation: See Documentation
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Security: security@clouddrove.com
See CHANGELOG.md for a detailed list of changes and version history.
Made with ❤️ by CloudDrove
Website •
GitHub •
Twitter