Security
Snip includes multiple security measures for safe deployment.
Security Headers
Snip automatically sets these headers on all responses:
| Header | Value | Purpose |
|---|---|---|
X-Content-Type-Options | nosniff | Prevents MIME type sniffing |
X-Frame-Options | DENY | Prevents clickjacking |
Referrer-Policy | strict-origin-when-cross-origin | Controls referrer information |
Permissions-Policy | geolocation=(), microphone=(), camera=() | Disables unnecessary APIs |
Content-Security-Policy | Restricted sources | Prevents XSS and data injection |
Rate Limiting
All endpoints are rate-limited to 120 requests per minute per IP. When exceeded, the server returns HTTP 429.
The rate limiter uses an in-memory map with automatic cleanup of expired entries.
Password Protection
Paste passwords are hashed with bcrypt (cost factor 12). The plaintext password is never stored.
- Password-protected pastes require the password for all access (view, raw, download, fork)
- The
/rawand/downloadendpoints also enforce password checks - Forking a protected paste requires the password
API Token Security
- Tokens are generated with 32 bytes of cryptographic randomness
- Only the SHA-256 hash is stored in the database
- Tokens are prefixed with
snip_for easy identification - Tokens can have optional expiration dates
- Last-used timestamp is tracked for audit purposes
Input Validation
- Paste content size is limited (default 10MB, configurable)
- Request body size is enforced at the middleware level
- SQL LIKE wildcards are escaped to prevent injection
- Content-Disposition filenames are sanitized
- Custom slugs are validated for uniqueness
Privacy
- QR codes are generated client-side -- no data sent to external services
- Password-protected pastes return empty content in list/search views
- No analytics or tracking scripts
- No cookies used for tracking (only for language preference)
Production Best Practices
Checklist for production deployment:
- Use HTTPS -- Always deploy behind a reverse proxy with TLS
- Set SNIP_JWT_SECRET -- Use a strong random string (
openssl rand -hex 32) - Set SNIP_BASE_URL -- Match your public URL exactly
- Regular backups -- Use the backup API or copy the SQLite file
- Monitor logs -- Check for unusual activity patterns
- Keep updated -- Watch the GitHub repo for security updates
- Restrict network -- Use firewall rules to limit access
- Run as non-root -- Use the Docker image or create a dedicated user
Responsible Disclosure
If you discover a security vulnerability, please report it responsibly. Do not open a public GitHub issue.
Send an email to the maintainer with:
- Description of the vulnerability
- Steps to reproduce
- Potential impact
- Suggested fix (if any)
Response timeline:
- 24-48 hours: Acknowledgment
- 1 week: Assessment and initial response
- 2-4 weeks: Fix and release
Security Architecture
Architecture
Client Request
|
v
[Rate Limiter] -- 429 if exceeded
|
v
[Security Headers] -- CSP, X-Frame-Options, etc.
|
v
[CORS] -- For API routes only
|
v
[Body Size Limit] -- 413 if too large
|
v
[Auth Middleware] -- JWT or API token (protected routes)
|
v
[Handler] -- Business logic
|
v
[Service Layer] -- Validation, password checking
|
v
[Store Layer] -- SQLite with parameterized queries