GuardAPI Logo
GuardAPI

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, run

DATABASE 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 os

HARDENING: 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’

System Alert • ID: 7207
Target: Bottle API
Potential Vulnerability

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.

RUN FREE SECURITY DIAGNOSTIC
GuardLabs Engine: ONLINE

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.