diff --git a/.jules/sentinel.md b/.jules/sentinel.md index 518c5af..a847428 100644 --- a/.jules/sentinel.md +++ b/.jules/sentinel.md @@ -9,3 +9,16 @@ Always use an environment variable (like `ALLOWED_ORIGINS`) to strictly define a **Prevention:** 1. Do not use wildcard `["*"]` for CORS in production setups, especially with authenticated routes. 2. Verify CORS setups using testing frameworks like Pytest or by configuring restricted inputs dynamically through the `.env` configuration. + +## 2024-05-18 - Hardcoded Admin Credentials Vulnerability + +**Vulnerability:** +The `backend/auth.py` file contained hardcoded admin credentials (`username != "admin"` or `password != "admin123"`) directly in the source code. This is a critical security vulnerability that exposes administrative access to anyone who can read the repository. Furthermore, the standard string comparison `!=` is vulnerable to timing attacks. + +**Learning:** +Hardcoded credentials are a common but severe risk, especially in initial project templates. Authentication checks should never use simple string comparisons, as it allows attackers to guess valid credentials character-by-character based on response time. + +**Prevention:** +1. Always store sensitive credentials (like passwords, API keys, admin usernames) in environment variables or a secure vault, never in source code. +2. Use `secrets.compare_digest(a.encode('utf-8'), b.encode('utf-8'))` for comparing sensitive strings to prevent timing attacks, and always encode to avoid TypeErrors with non-ASCII characters. +3. Fail securely by raising a 500 error if required authentication configuration (like environment variables) is missing, rather than defaulting to an insecure state. diff --git a/backend/auth.py b/backend/auth.py index 1f396ff..2347e3b 100644 --- a/backend/auth.py +++ b/backend/auth.py @@ -1,7 +1,18 @@ +import os +import secrets from fastapi import HTTPException def authenticate_admin(username: str, password: str): - # Dummy authentication logic - if username != "admin" or password != "admin123": + admin_username = os.environ.get("ADMIN_USERNAME") + admin_password = os.environ.get("ADMIN_PASSWORD") + + if not admin_username or not admin_password: + raise HTTPException(status_code=500, detail="Admin credentials are not configured on the server.") + + is_username_correct = secrets.compare_digest(username.encode('utf-8'), admin_username.encode('utf-8')) + is_password_correct = secrets.compare_digest(password.encode('utf-8'), admin_password.encode('utf-8')) + + if not (is_username_correct and is_password_correct): raise HTTPException(status_code=401, detail="Invalid username or password") + return {"message": "Login successful"}