8.0 KiB
Security
FlaskPaste is designed with security as a primary concern. This document describes security features, best practices, and responsible disclosure procedures.
Security Features
Authentication
Client Certificate Authentication (mTLS)
FlaskPaste supports mutual TLS authentication via reverse proxy:
- Reverse proxy terminates TLS and validates client certificates
- Proxy extracts SHA1 fingerprint and passes via
X-SSL-Client-SHA1header - FlaskPaste uses fingerprint for ownership tracking and authorization
# nginx example
location / {
proxy_pass http://127.0.0.1:5000;
proxy_set_header X-SSL-Client-SHA1 $ssl_client_fingerprint;
}
Proxy Trust Validation
Defense-in-depth against header spoofing:
export FLASKPASTE_PROXY_SECRET="shared-secret"
The proxy must send X-Proxy-Secret header; requests without valid secret are treated as anonymous.
Password Protection
Pastes can be password-protected using PBKDF2-HMAC-SHA256:
- 600,000 iterations (OWASP 2023 recommendation)
- 32-byte random salt per password
- Constant-time comparison prevents timing attacks
- Passwords never logged or stored in plaintext
# Create protected paste
curl -H "X-Paste-Password: secret" --data-binary @file.txt https://paste.example.com/
# Access protected paste
curl -H "X-Paste-Password: secret" https://paste.example.com/abc123/raw
End-to-End Encryption
CLI supports client-side AES-256-GCM encryption:
- Key generated locally, never sent to server
- Key appended to URL as fragment (
#key) which browsers never transmit - Server stores only opaque ciphertext
- Zero-knowledge: server cannot read content
./fpaste create -e secret.txt
# Returns: https://paste.example.com/abc123#<base64-key>
Abuse Prevention
Content-Hash Deduplication
Prevents spam flooding by throttling repeated identical submissions:
FLASKPASTE_DEDUP_WINDOW=3600 # 1 hour window
FLASKPASTE_DEDUP_MAX=3 # Max 3 identical submissions
Proof-of-Work
Computational puzzle prevents automated spam:
FLASKPASTE_POW_DIFFICULTY=20 # Leading zero bits required
FLASKPASTE_POW_TTL=300 # Challenge validity (seconds)
Entropy Enforcement
Optional minimum entropy requirement to enforce encrypted uploads:
FLASKPASTE_MIN_ENTROPY=6.0 # Bits per byte (encrypted ~7.5-8.0)
FLASKPASTE_MIN_ENTROPY_SIZE=256 # Only check content >= this size
URL Shortener Security
Open Redirect Prevention
Short URL creation validates target URLs:
- Only
httpandhttpsschemes allowed (rejectsjavascript:,data:,ftp:,file:) - Network location (hostname) required — rejects scheme-only URLs
- Maximum URL length: 2048 bytes
- Short IDs: 8-char base62 (
[a-zA-Z0-9]) withsecrets.choice()for unpredictability - Redirect responses include
Cache-Control: no-store, no-cacheto prevent caching
Access Controls
- Creation: rate-limited + proof-of-work (same as paste creation)
- Redirect: lookup rate limiting prevents enumeration
- Deletion: owner authentication required
- Listing: authentication required, shows only own URLs
Security Headers
All responses include:
| Header | Value |
|---|---|
Strict-Transport-Security |
max-age=31536000; includeSubDomains |
X-Content-Type-Options |
nosniff |
X-Frame-Options |
DENY |
X-XSS-Protection |
1; mode=block |
Content-Security-Policy |
default-src 'none' |
Referrer-Policy |
no-referrer |
Permissions-Policy |
geolocation=(), microphone=(), camera=() |
Cache-Control |
no-store, no-cache, must-revalidate |
Pragma |
no-cache |
Request Tracing
All requests receive X-Request-ID header for log correlation and debugging. Pass your own ID to trace requests through reverse proxies.
Input Validation
Paste IDs
- Hexadecimal only (
[a-f0-9]+) - Configurable length (default 12 characters)
- Validated on all endpoints
Short URL IDs
- Base62 only (
[a-zA-Z0-9]+) - 8 characters (configurable via
FLASKPASTE_SHORT_ID_LENGTH) - Validated on all
/s/endpoints
MIME Types
- Magic byte detection for binary formats
- Sanitized against injection
- Only safe characters allowed:
[a-z0-9!#$&\-^_.+]
Size Limits
FLASKPASTE_MAX_ANON=3145728 # 3 MiB for anonymous
FLASKPASTE_MAX_AUTH=52428800 # 50 MiB for authenticated
Password Limits
- Maximum 1024 characters (prevents DoS via hashing)
- Unicode supported
- Special characters allowed
SQL Injection Prevention
All database queries use parameterized statements:
# Correct - parameterized
db.execute("SELECT * FROM pastes WHERE id = ?", (paste_id,))
# Never - string concatenation
db.execute(f"SELECT * FROM pastes WHERE id = '{paste_id}'")
Database Security
- SQLite with WAL mode for better concurrency
- Foreign keys enforced
- Automatic cleanup of expired content
- No sensitive data in plaintext (passwords are hashed)
Deployment Recommendations
Reverse Proxy
Always deploy behind a TLS-terminating reverse proxy:
┌─────────┐ TLS ┌─────────┐ HTTP ┌───────────┐
│ Client │ ──────────── │ nginx │ ──────────── │ FlaskPaste│
│ │ mTLS opt │ HAProxy │ local │ │
└─────────┘ └─────────┘ └───────────┘
Container Security
# Run as non-root
USER app
# Read-only filesystem where possible
# Mount /app/data as writable volume
Network Isolation
- FlaskPaste should only listen on localhost or internal network
- Reverse proxy handles external traffic
- Use firewall rules to restrict direct access
Secrets Management
# Use strong, unique secrets
FLASKPASTE_PROXY_SECRET="$(openssl rand -hex 32)"
FLASKPASTE_POW_SECRET="$(openssl rand -hex 32)"
Security Checklist
Before Deployment
- Deploy behind TLS-terminating reverse proxy
- Configure
FLASKPASTE_PROXY_SECRETif using auth headers - Enable proof-of-work if public-facing
- Set appropriate size limits
- Configure paste expiry
Ongoing
- Monitor logs for suspicious activity
- Keep dependencies updated
- Review access patterns
- Rotate secrets periodically
- Test backup/restore procedures
Known Limitations
- No user accounts - PKI handles identity
- Single-node only - SQLite limits horizontal scaling
Reporting Vulnerabilities
If you discover a security vulnerability:
- Do not open a public issue
- Email security concerns to the repository maintainer
- Include:
- Description of the vulnerability
- Steps to reproduce
- Potential impact
- Suggested fix (if any)
We aim to acknowledge reports within 48 hours and provide a fix timeline within 7 days.
Security Updates
Security fixes are released as soon as possible. Subscribe to repository releases for notifications.
Threat Model
In Scope
- Unauthorized access to pastes
- Content injection attacks
- Authentication bypass
- Information disclosure
- Denial of service (application-level)
- Open redirect via URL shortener
Out of Scope
- Physical access to server
- Compromise of reverse proxy
- Client-side vulnerabilities
- Network-level DoS
- Social engineering
Version History
| Version | Security Changes |
|---|---|
| 1.6.0 | URL shortener with open redirect prevention, scheme allowlist, target URL validation |
| 1.5.0 | Pentest remediation (15 items): timing attack prevention, serial collision detection, lookup rate limiting, content hash locking, anti-flood memory limits, CLI path validation, SSL hostname verification, config permission checks |
| 1.4.0 | Anti-flood dynamic PoW, IP-based rate limiting, audit logging |
| 1.2.0 | Password protection with PBKDF2, code modernization |
| 1.1.0 | E2E encryption, entropy enforcement, burn-after-read |
| 1.0.0 | Initial release with core security features |