Description
Two security-sensitive configuration values in finbot/config.py and finbot/main.py are set to insecure defaults. Any deployment that does not explicitly override them in .env ships with exploitable settings out of the box , including self-hosted CTF instances spun up by participants.
Finding 1 - SESSION_COOKIE_SECURE defaults to False
File: finbot/config.py · Line 80
SESSION_COOKIE_SECURE: bool = False # Set to True in production with https
The Secure cookie attribute tells the browser to never send the cookie over a plain HTTP connection. With it set to False by default, the session cookie (finbot_session) is transmitted in cleartext on any non-HTTPS connection.
Since finbot_session is the sole authentication credential for both the vendor and admin portals, an attacker on the same network can passively capture it and take over any account.
Observed Set-Cookie header with current defaults:
Set-Cookie: finbot_session=<token>; HttpOnly; SameSite=Lax; Path=/
⚠️ Secure flag is absent.
Proposed fix:
# config.py - line 80
SESSION_COOKIE_SECURE: bool = True # Set to False in .env for local HTTP dev only
Finding 2 - ProxyHeadersMiddleware trusts all upstream hosts ("*")
File: finbot/main.py · Line 152
app.add_middleware(ProxyHeadersMiddleware, trusted_hosts=["*"])
ProxyHeadersMiddleware reads X-Forwarded-For to determine the real client IP when deployed behind a reverse proxy. With trusted_hosts=["*"], any client — not just the reverse proxy — can forge their IP by adding a header to their request:
curl -H "X-Forwarded-For: 127.0.0.1" http://localhost:8000/api/session/status
The server will record 127.0.0.1 as the client IP in session logs, MagicLinkToken.ip_address, and CTF event audit records — all of which are now meaningless for security investigations.
Impact:
- Forged client IPs poison session audit logs and CTF event records
- Weakens the IP-based hijack detection in
SessionContext.detect_suspicious_activity()
- Will bypass any future per-IP rate limiting added to high-risk endpoints
Proposed fix:
# main.py - line 152
import os
_trusted_proxies = os.getenv("TRUSTED_PROXY_IPS", "127.0.0.1").split(",")
app.add_middleware(ProxyHeadersMiddleware, trusted_hosts=_trusted_proxies)
Add to .env.example:
# Comma-separated IPs of trusted reverse proxies (Railway, nginx, etc.)
# TRUSTED_PROXY_IPS=127.0.0.1
Steps to Reproduce
Finding 1 - Missing Secure flag
- Start the app without setting
SESSION_COOKIE_SECURE=true in .env
- Submit an email on the sign-in page (
POST /auth/magic-link)
- Inspect the
Set-Cookie response header — the Secure attribute is absent
Finding 2 - IP spoofing
- Start the app locally
- Run:
curl -s -H "X-Forwarded-For: 1.2.3.4" http://localhost:8000/api/session/status
- Check server logs — the request is recorded with IP
1.2.3.4 instead of the real client IP
Affected Files
| File |
Line |
Issue |
finbot/config.py |
80 |
SESSION_COOKIE_SECURE: bool = False |
finbot/main.py |
152 |
trusted_hosts=["*"] |
.env.example |
— |
Missing guidance for both settings |
Description
Two security-sensitive configuration values in
finbot/config.pyandfinbot/main.pyare set to insecure defaults. Any deployment that does not explicitly override them in.envships with exploitable settings out of the box , including self-hosted CTF instances spun up by participants.Finding 1 -
SESSION_COOKIE_SECUREdefaults toFalseFile:
finbot/config.py· Line 80The
Securecookie attribute tells the browser to never send the cookie over a plain HTTP connection. With it set toFalseby default, the session cookie (finbot_session) is transmitted in cleartext on any non-HTTPS connection.Since
finbot_sessionis the sole authentication credential for both the vendor and admin portals, an attacker on the same network can passively capture it and take over any account.Observed
Set-Cookieheader with current defaults:Proposed fix:
Finding 2 -
ProxyHeadersMiddlewaretrusts all upstream hosts ("*")File:
finbot/main.py· Line 152ProxyHeadersMiddlewarereadsX-Forwarded-Forto determine the real client IP when deployed behind a reverse proxy. Withtrusted_hosts=["*"], any client — not just the reverse proxy — can forge their IP by adding a header to their request:curl -H "X-Forwarded-For: 127.0.0.1" http://localhost:8000/api/session/statusThe server will record
127.0.0.1as the client IP in session logs,MagicLinkToken.ip_address, and CTF event audit records — all of which are now meaningless for security investigations.Impact:
SessionContext.detect_suspicious_activity()Proposed fix:
Add to
.env.example:Steps to Reproduce
Finding 1 - Missing Secure flag
SESSION_COOKIE_SECURE=truein.envPOST /auth/magic-link)Set-Cookieresponse header — theSecureattribute is absentFinding 2 - IP spoofing
curl -s -H "X-Forwarded-For: 1.2.3.4" http://localhost:8000/api/session/status1.2.3.4instead of the real client IPAffected Files
finbot/config.pySESSION_COOKIE_SECURE: bool = Falsefinbot/main.pytrusted_hosts=["*"].env.example