Hardening: basic-memory mcp HTTP/SSE transport defaults to 0.0.0.0 with no auth — contradicts SECURITY.md
Class: unsafe default. No exploit/PoC attached — reporting publicly per your SECURITY.md's own guidance, since this is a config-default hardening issue with no novel exploitation primitive.
What
basic-memory mcp --transport streamable-http (and sse) defaults --host to 0.0.0.0:
src/basic_memory/cli/commands/mcp.py (@ 3bf2d523):
host: str = typer.Option(
"0.0.0.0", help="Host for HTTP transports (use 0.0.0.0 to allow external connections)"
),
The HTTP transport is served with no authentication and no Origin/Host allow-list. The only middleware registered on the server is MCPClientInfoMiddleware (src/basic_memory/mcp/server.py:272); CLIAuth there is for loading the outbound cloud OAuth token, not for gating inbound requests. So a single basic-memory mcp --transport streamable-http binds every knowledge-base tool — write_note, read_note, read_content, delete_note, create_memory_project, etc. — to all interfaces, unauthenticated, reachable by anyone on the LAN.
Why this is worth fixing
It directly contradicts the project's own SECURITY.md:
- Basic Memory does not open network ports by default. The MCP server uses stdio; the optional REST API is intended for localhost use.
- If exposing the REST API, bind it only to localhost.
The default is to open a port on all interfaces the moment a user picks an HTTP transport, and there is no localhost binding by default. A user following the docs to run the recommended web transport gets the opposite of what SECURITY.md promises. create_memory_project also lets a caller point a project at an arbitrary local path (by design for a personal tool), which raises the impact of the port being reachable off-host.
Related: with no Host/Origin check, a 0.0.0.0 (or even 127.0.0.1) listener is exposed to DNS-rebinding from a browser tab. I have not verified whether the underlying fastmcp 4.x / mcp stack adds any origin protection of its own, so I'm flagging this as a consideration rather than a confirmed gap — worth a look while touching this code.
Suggested fix (minimal)
- Default
--host to 127.0.0.1; keep 0.0.0.0 as an explicit opt-in.
- When the user does pass a non-loopback host, log a one-line startup warning that the transport is unauthenticated and reachable off-host.
- (Optional, stronger) add an allowed-hosts / origin check for the HTTP transports to close the rebinding surface.
Happy to open a PR for (1)+(2) — it's a one-line default change plus a warning. Just confirm you'd take it and whether you'd rather keep 0.0.0.0 documented for the container path.
Prior art checked
No matching open/closed issues, 0 security advisories, private vuln reporting enabled. Filing publicly because this is hardening with no exploit; if you'd prefer this privately for any reason, say the word and I'll move it to a security advisory.
— TonyDzi (Palo Alto AI Research Lab) · this is a tiny piece of a bigger machine — a second brain + multi-agent fleet with persistent memory: github.com/tonydzi · DMs open. (Report drafted with an AI co-founder under my review.)
Hardening:
basic-memory mcpHTTP/SSE transport defaults to0.0.0.0with no auth — contradicts SECURITY.mdClass: unsafe default. No exploit/PoC attached — reporting publicly per your SECURITY.md's own guidance, since this is a config-default hardening issue with no novel exploitation primitive.
What
basic-memory mcp --transport streamable-http(andsse) defaults--hostto0.0.0.0:src/basic_memory/cli/commands/mcp.py(@3bf2d523):The HTTP transport is served with no authentication and no
Origin/Hostallow-list. The only middleware registered on the server isMCPClientInfoMiddleware(src/basic_memory/mcp/server.py:272);CLIAuththere is for loading the outbound cloud OAuth token, not for gating inbound requests. So a singlebasic-memory mcp --transport streamable-httpbinds every knowledge-base tool —write_note,read_note,read_content,delete_note,create_memory_project, etc. — to all interfaces, unauthenticated, reachable by anyone on the LAN.Why this is worth fixing
It directly contradicts the project's own SECURITY.md:
The default is to open a port on all interfaces the moment a user picks an HTTP transport, and there is no localhost binding by default. A user following the docs to run the recommended web transport gets the opposite of what SECURITY.md promises.
create_memory_projectalso lets a caller point a project at an arbitrary local path (by design for a personal tool), which raises the impact of the port being reachable off-host.Related: with no
Host/Origincheck, a0.0.0.0(or even127.0.0.1) listener is exposed to DNS-rebinding from a browser tab. I have not verified whether the underlyingfastmcp4.x /mcpstack adds any origin protection of its own, so I'm flagging this as a consideration rather than a confirmed gap — worth a look while touching this code.Suggested fix (minimal)
--hostto127.0.0.1; keep0.0.0.0as an explicit opt-in.Happy to open a PR for (1)+(2) — it's a one-line default change plus a warning. Just confirm you'd take it and whether you'd rather keep
0.0.0.0documented for the container path.Prior art checked
No matching open/closed issues, 0 security advisories, private vuln reporting enabled. Filing publicly because this is hardening with no exploit; if you'd prefer this privately for any reason, say the word and I'll move it to a security advisory.
— TonyDzi (Palo Alto AI Research Lab) · this is a tiny piece of a bigger machine — a second brain + multi-agent fleet with persistent memory: github.com/tonydzi · DMs open. (Report drafted with an AI co-founder under my review.)