Skip to content

2.2.3 - Bug fixes, performance gains

Choose a tag to compare

@peva3 peva3 released this 28 Mar 15:54
· 6 commits to main since this release

[2.2.3] - 2026-03-27

Security Fixes

  • SQL injection anti-pattern in index creation (database.py:278-281): Changed f-string interpolation in DDL helper to parameterized query using text(...).bindparams(...). The index name was hardcoded so not directly exploitable, but the pattern could be copied to user-facing code.
  • Timing attack on admin API key comparison (state.py:467): Changed string != comparison to hmac.compare_digest() to prevent timing side-channel attacks on the admin API key.

Bug Fixes

  • VRAM state inconsistency on model load failure (vram_manager.py:120-148): Added snapshot of loaded_models before VRAM freeing; restores snapshot if load_model() raises or VRAMExceededError occurs. Previously, a failed load could free VRAM without adding the model.
  • load_model always returns True in Ollama backend (ollama.py:330-388): Returns False when the model doesn't exist, when both load attempts fail, or on generic exceptions. Previously all code paths returned True even on genuine failures.
  • Duplicate background task registration (lifecycle.py:197-218): Removed duplicate registration of background_cache_cleanup_task and background_dlq_retry_task that were creating redundant coroutines.

Performance Improvements

  • Bulk delete for expired cache entries (persistent_cache.py): Replaced O(N) row-by-row session.delete() loop with single session.execute(delete(Model).where(...)) bulk SQL delete.
  • Efficient cache count queries (persistent_cache.py): Replaced len(session.execute(...).scalars().all()) with session.scalar(select(func.count()).where(...)) to avoid loading all rows into memory.
  • Bounded prompt analysis cache (router.py): Changed _PROMPT_ANALYSIS_CACHE from unbounded dict to OrderedDict with max 4096 entries and LRU eviction on write. Added move_to_end on read access.
  • Bounded benchmark cache (benchmark_db.py): Changed _benchmarks_for_models_cache from unbounded frozenset-keyed dict to OrderedDict with max 512 entries and LRU eviction.
  • Async DB call for feedback scores (router.py:1291): Changed synchronous self._get_model_feedback_scores() call in async _keyword_dispatch to await asyncio.to_thread(...) to avoid blocking the event loop.
  • Async file I/O for provider.db download (lifecycle.py:441): Wrapped blocking open(...).write(...) in await asyncio.to_thread(_write_temp) to prevent event loop stalls during download.
  • Single-transaction bulk upsert (benchmark_db.py:166-186): Moved session and commit outside the per-item loop so all benchmark rows are written in a single transaction.