Fetching from the wire…
Public story · 2026-09-09 · high
A missing owner check let a batch write with someone else's session ID overwrite that user's row.
Why now: Agno dated the fix to its 3.0.8 release on GitHub.
Agno's SqliteDb and AsyncSqliteDb adapters let one user's data overwrite another's through the bulk upsert path, per the project's 3.0.8 release notes. Calling upsert_sessions() with a batch that included someone else's session_id would reassign that row and replace its contents.
Any app calling bulk upsert with session IDs pulled from user input or a shared queue was exposed. A batch didn't need special permissions to hit another tenant's row, just the right ID in the list.
Agno had already built a single-row owner check for SQLite, but it only ran on single-row writes. The bulk path skipped it entirely. Version 3.0.8 applies the same check to every row in a bulk upsert.
Rows that fail the check now get dropped from the batch instead of overwriting anything. They're also omitted from the returned list, matching how the Postgres adapter already worked. The release separately stops the SQLite adapters from double-encoding session JSON.
The fix is a patch version, so the upgrade should be low-friction. The release notes don't say whether other bulk operations in the SQLite adapters still skip per-row checks that the single-row path enforces. That gap tends to stay invisible until someone runs a batch large enough to include an ID nobody expected.
Each link below shares sources, entities, or timing with this story.
MCPConfig(stateless=True) serves /mcp with no session tracking, so any replica answers any request. The cost is server-initiated notifications and SSE resumability, which is why it's off by default. MCPTools(protocol_mode=...) picks the protocol era to negotiate, defaulting to...
Runs now get their own agno_runs table with real columns instead of being packed into the session row, which takes session write amplification from O(N²) to O(N) and removes the DynamoDB and Firestore item-size ceiling (GitHub). offload_tool_results=True writes any tool result...
Triple-stream retrieval (BM25 keyword, vector embeddings, knowledge-graph traversal) fused via Reciprocal Rank Fusion on the iii engine, with SQLite for state and an in-memory vector index, no external database. The economic claim: ~170K tokens/year (~$10) versus ~650K tokens...
The 8-years-planned migration landed this weekend via a 735-line, 30-commit change, and notably ended on SQLite instead of the PostgreSQL originally targeted in 2018. The site now runs a 3.8GB content DB plus separate cache, queue, and security databases on a single box, with...
MCPConfig.tools now accepts Agent, Team and Workflow instances plus Toolkit objects, exposing each as its own named MCP tool. You call chief, not run_agent(agent_id="chief"). Toolkits publish one MCP tool per registered method, narrowed by the toolkit's own enable/include/excl...
IPython 9.17 registers script magics lazily and recreates them on lookup, so Agno's method of removing bash from the cell-magic table stopped disabling it. A kernel explicitly configured to forbid shell access executed %%bash anyway. The fix materializes the script-magic provi...
MindPattern daily
One email a day at 7 AM. Sources and a take on every story. Unsubscribe anytime.