fix: move OpenAI API key from client-side session cookie to server-side storage (CWE-200)#63
Open
sebastiondev wants to merge 1 commit intoBAI-LAB:mainfrom
Open
Conversation
Flask default sessions are signed but not encrypted — the session payload is base64-visible in the cookie. Storing the OpenAI API key in session["memory_config"] exposed it to anyone who can read the cookie (network interception, XSS, browser extensions, etc.). Move the config dict (containing api_key, base_url, model) into the server-side memory_systems dict alongside the Memoryos instance. Only the opaque session_id token is now stored in the cookie. CWE-200: Exposure of Sensitive Information to an Unauthorized Actor
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Vulnerability Summary
CWE: CWE-200 — Exposure of Sensitive Information to an Unauthorized Actor
Severity: Medium
File:
memoryos-playground/memdemo/app.pyLines: L91–L102 (before fix)
Data Flow
Flask's default session implementation uses signed but not encrypted cookies. As Flask's own documentation states: "The session cookie is only signed, not encrypted. Users can read the contents."
This means the OpenAI API key is visible in plaintext (base64-decoded) to:
innerHTMLsinks with unsanitized LLM responses)The key is not only stored once — it is retransmitted with every request in the Cookie header and with every response in the Set-Cookie header, multiplying exposure windows.
Exploit Sketch
Fix Description
Approach: Move the API key (and related config) from the client-side Flask session cookie to the existing server-side
memory_systemsdictionary.What Changed
The
memory_systemsdict previously stored only theMemoryosinstance per session. This fix restructures each entry to hold both the system and its config:All 7 access points where
memory_systems[session_id]was used as aMemoryosinstance are updated to usememory_systems[session_id]["system"]. The/clear_memoryendpoint, which previously read the API key back fromsession["memory_config"], now reads it from the server-sideentry["config"].Rationale
memory_session_id(an opaque token) — the API key has no reason to leave the server.Test Results
Manual Verification
chat,get_memory_state,trigger_analysis,personality_analysis,clear_memory,import_conversations, andinit_memoryall correctly reference the new{'system': ..., 'config': ...}structure./clear_memoryreinitializaton now retrieves config fromentry["config"](server-side) instead ofsession.get("memory_config")(client cookie).memory_session_id— an opaque hex token with no sensitive data.Diff Verification
Disprove Analysis
We attempted to disprove and poke holes in our own finding. Summary of results:
Authentication Check
No authentication or authorization exists on any endpoint. The app is completely open to anyone who can reach port 5019.
Network Check
The app binds to
0.0.0.0:5019withdebug=True. No CORS restrictions, no HTTPS, noALLOWED_HOSTS. It is internet-accessible when deployed.Deployment Context
The README instructs users to run
python3 app.pydirectly. A hosted version exists atbaijia.online/memoryos/, confirming it is intended for internet-facing deployment. No reverse proxy, VPN, or TLS configuration is mentioned.Caller Trace
session["memory_config"]is written ininit_memory()at line 102. The API key flows from user POST body →session["memory_config"]["api_key"]→ Flask session cookie (sent to browser as base64-encoded, signed but not encrypted data). It is read back inclear_memory()at line 355 to reinitialize the memory system.Input Validation
No input sanitization, escaping, or validation of the API key before storing it in the session cookie.
Prior Reports / Security Policy
No prior security issues reported on this repository. No
SECURITY.mdexists.Mitigations Found
None. No cookie flags (
HttpOnly,Secure,SameSite), no TLS, no CSP headers, no auth.Fix Adequacy Assessment
The fix is meaningful but scoped. It addresses the specific CWE-200 issue of storing secrets in client-readable cookies. It does not address parallel concerns:
/init_memoryPOST body (one-time event vs. persistent cookie retransmission).debug=Trueremains, exposing the Werkzeug debugger.HttpOnly,Secure, orSameSitecookie flags.innerHTMLXSS sinks exist in the frontend.These are noted as separate concerns for your awareness, not as reasons to reject this fix. Each represents a distinct vulnerability with a distinct remediation.
Verdict: CONFIRMED_VALID (Confidence: High)
The vulnerability is real, well-understood, and documented by Flask itself. The fix meaningfully reduces the attack surface by removing the API key from persistent, repeatedly-transmitted client-side storage and moving it to server-side-only storage.
Additional Notes for Maintainers
This PR intentionally limits scope to the CWE-200 session cookie issue. For defense-in-depth, you may also want to consider:
debug=Truetodebug=Falsefor any deployment (Werkzeug debugger can enable RCE)httponly=True,samesite="Lax") on the Flask sessioninnerHTMLin the frontendThank you for your work on MemoryOS! Happy to discuss or adjust anything in this PR.