Flask SECRET_KEY falls back to a public value, enabling session forgery
Hello ydf0509,
When FUNWEB_SECRET_KEY is unset, Funboost signs Flask session cookies with the public fallback mtfy54321. An attacker can forge a Flask-Login session for a configured account and bypass its password check.
Evidence
funboost/funweb/app.py:58 sets app.secret_key = os.getenv('FUNWEB_SECRET_KEY', "mtfy54321"). The environment override exists, but startup does not reject a missing or default value.
start_funboost_web_manager defaults to host="0.0.0.0" and port=27018, exposing the manager on all interfaces when started with defaults.
load_user checks the supplied ID against the in-memory users list, then returns a User. It does not check whether the session was issued by a successful login or is still valid on the server. The default list contains the admin account.
- The application and its management blueprints protect routes with
@login_required, including /deploy/save and /deploy/<name>/start. The deploy handler stores the caller's start_cmd; _start_process executes it with subprocess.Popen(..., shell=True).
- Flask's default session interface stores signed session data in the client cookie. The application does not configure a server-side session store or access-token revocation state.
Proof of concept
Static reproduction steps for a deployment using the fallback key (not run against a live deployment): sign a Flask-Login session for the default admin account, then use it on a protected route:
COOKIE=$(flask-unsign --sign \
--cookie "{'_user_id':'admin','_fresh':True}" \
--secret 'mtfy54321')
curl -i -H "Cookie: session=$COOKIE" http://<host>:27018/
The root route accepts the authenticated session. With the same cookie, an attacker can call /deploy/save to store a deployment command and /deploy/<name>/start to execute it as the Funboost web process. The deployment routes require the application's Redis-backed deploy configuration to be available.
Impact
An attacker who can reach the web manager and knows an account ID in its configured in-memory user list can bypass that account's password and use its authenticated routes. With the default account list, admin is a known ID. The deploy management routes can turn this into command execution with the web process's privileges when that feature's Redis backend is configured.
Remediation
The code already supports FUNWEB_SECRET_KEY. Require it at startup for deployments and reject mtfy54321 and other placeholders. Use a unique high-entropy value, and rotate it to invalidate cookies signed with the fallback.
Prior disclosure check
On September 28, 2026, I checked public open and closed Issues and pull requests, searched their indexed text for mtfy54321, FUNWEB_SECRET_KEY, Flask, session, and security terms, and checked the repository's published advisories and security policy files. I found no prior public report for this finding. GitHub Discussions are disabled; private disclosures are outside this check.
Related works
This report is part of my ongoing security research. Please feel free to @mention me if you have any questions. I would be glad to make a small contribution to the security of Funboost.
Flask SECRET_KEY falls back to a public value, enabling session forgery
Hello ydf0509,
When
FUNWEB_SECRET_KEYis unset, Funboost signs Flask session cookies with the public fallbackmtfy54321. An attacker can forge a Flask-Login session for a configured account and bypass its password check.Evidence
funboost/funweb/app.py:58setsapp.secret_key = os.getenv('FUNWEB_SECRET_KEY', "mtfy54321"). The environment override exists, but startup does not reject a missing or default value.start_funboost_web_managerdefaults tohost="0.0.0.0"andport=27018, exposing the manager on all interfaces when started with defaults.load_userchecks the supplied ID against the in-memoryuserslist, then returns aUser. It does not check whether the session was issued by a successful login or is still valid on the server. The default list contains theadminaccount.@login_required, including/deploy/saveand/deploy/<name>/start. The deploy handler stores the caller'sstart_cmd;_start_processexecutes it withsubprocess.Popen(..., shell=True).Proof of concept
Static reproduction steps for a deployment using the fallback key (not run against a live deployment): sign a Flask-Login session for the default
adminaccount, then use it on a protected route:The root route accepts the authenticated session. With the same cookie, an attacker can call
/deploy/saveto store a deployment command and/deploy/<name>/startto execute it as the Funboost web process. The deployment routes require the application's Redis-backed deploy configuration to be available.Impact
An attacker who can reach the web manager and knows an account ID in its configured in-memory user list can bypass that account's password and use its authenticated routes. With the default account list,
adminis a known ID. The deploy management routes can turn this into command execution with the web process's privileges when that feature's Redis backend is configured.Remediation
The code already supports
FUNWEB_SECRET_KEY. Require it at startup for deployments and rejectmtfy54321and other placeholders. Use a unique high-entropy value, and rotate it to invalidate cookies signed with the fallback.Prior disclosure check
On September 28, 2026, I checked public open and closed Issues and pull requests, searched their indexed text for
mtfy54321,FUNWEB_SECRET_KEY, Flask, session, and security terms, and checked the repository's published advisories and security policy files. I found no prior public report for this finding. GitHub Discussions are disabled; private disclosures are outside this check.Related works
This report is part of my ongoing security research. Please feel free to @mention me if you have any questions. I would be glad to make a small contribution to the security of Funboost.