Files
flaskpaste/SECURITY.md
Username 3059d533bc
Some checks failed
CI / Lint & Format (push) Failing after 17s
CI / Tests (push) Has been skipped
CI / Memory Leak Check (push) Has been skipped
CI / Security Scan (push) Successful in 22s
docs: update documentation after pentest remediation
- TASKLIST.md: add pentest tasks to completed section
- TODO.md: add observation about pentest completion
- ROADMAP.md: update test count (301), add decision log entry
- PROJECT.md: update test count (301)
- SECURITY.md: remove obsolete limitations, add v1.5.0 changes
2025-12-24 23:33:15 +01:00

7.1 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:

  1. Reverse proxy terminates TLS and validates client certificates
  2. Proxy extracts SHA1 fingerprint and passes via X-SSL-Client-SHA1 header
  3. 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

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

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_SECRET if 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

  1. No user accounts - PKI handles identity
  2. Single-node only - SQLite limits horizontal scaling

Reporting Vulnerabilities

If you discover a security vulnerability:

  1. Do not open a public issue
  2. Email security concerns to the repository maintainer
  3. 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)

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.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