Fix Broken User Authentication in Bottle
Bottle is a minimalist framework that offers zero built-in security for authentication. Most developers fail by storing plaintext passwords and using unsigned cookies, making the application vulnerable to credential stuffing and session hijacking. This guide demonstrates how to transition from a trivial, broken implementation to a hardened authentication flow.
The Vulnerable Pattern
from bottle import route, request, response, runDATABASE SIMULATION
users = {‘admin’: ‘password123’}
@route(‘/login’, method=‘POST’) def login(): username = request.forms.get(‘username’) password = request.forms.get(‘password’)
# VULNERABILITY 1: Plaintext password comparison if username in users and users[username] == password: # VULNERABILITY 2: Unsigned cookie (easily spoofed) response.set_cookie('user_id', username) return 'Logged in' return 'Access Denied'
@route(‘/admin’) def admin(): # VULNERABILITY 3: Trusting client-side data without verification user = request.get_cookie(‘user_id’) if user == ‘admin’: return ‘Welcome to the inner sanctum’ return ‘Unauthorized’
The Secure Implementation
The secure implementation addresses three critical failures. First, it replaces plaintext comparison with Argon2id, a memory-hard hashing algorithm that resists GPU-based brute forcing. Second, it utilizes Bottle's 'secret' parameter to create HMAC-signed cookies; if an attacker modifies the 'session_id', the signature check fails. Third, it enforces 'httponly' and 'secure' flags, mitigating session theft via XSS and ensuring tokens are never transmitted over unencrypted HTTP.
from bottle import route, request, response, run, default_app from passlib.hash import argon2 import osHARDENING: Use environment variables for secrets
SECRET_KEY = os.environ.get(‘APP_SECRET’, ‘super-secret-random-string’)
DATABASE SIMULATION (Passwords hashed with Argon2)
users = {‘admin’: ‘$argon2id$v=19$m=65536,t=3,p=4$6Y…truncated’}
@route(‘/login’, method=‘POST’) def login(): username = request.forms.get(‘username’) password = request.forms.get(‘password’)
user_hash = users.get(username) # FIX 1: Constant-time hash verification if user_hash and argon2.verify(password, user_hash): # FIX 2: Signed, HttpOnly, Secure cookies to prevent tampering and XSS access response.set_cookie('session_id', username, secret=SECRET_KEY, httponly=True, secure=True, samesite='Lax') return 'Authenticated' return 'Invalid Credentials'
@route(‘/admin’) def admin(): # FIX 3: Verify cryptographic signature of the cookie user = request.get_cookie(‘session_id’, secret=SECRET_KEY) if user == ‘admin’: return ‘Secure Admin Panel’ return ‘Unauthorized’
Your Bottle API
might be exposed to Broken User Authentication
74% of Bottle apps fail this check. Hackers use automated scanners to find this specific flaw. Check your codebase before they do.
Free Tier • No Credit Card • Instant Report
Verified by Ghost Labs Security Team
This content is continuously validated by our automated security engine and reviewed by our research team. Ghost Labs analyzes over 500+ vulnerability patterns across 40+ frameworks to provide up-to-date remediation strategies.