mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-08-18 22:37:58 +00:00
The email auto-calendar pass (settings.email_auto_calendar / the extract_email_events task) scans recently received mail and lets an LLM create / update / cancel calendar events. Two problems made it a cross-tenant, remotely triggerable hole: 1. No owner scoping. _auto_summarize_pass(account_id=None) fans out over EVERY enabled account of EVERY user. For each message it fetched an upcoming-events snapshot with NO owner filter (all tenants' events) and handed those uids + titles to the extraction LLM, then executed the model's ops via do_manage_calendar(...) with owner=None. do_manage_calendar only filters by owner when owner is not None, so create/update/delete ran across ALL users' calendars. Net: every user's event titles/times were disclosed to the model, and the model could cancel/move/duplicate any tenant's events by uid. 2. No prompt-injection wrapping. The raw email From/Subject/body were interpolated straight into an instruction-shaped extraction prompt (unlike the chat path, which wraps external text via src/prompt_security). Anyone who can email a user whose instance has auto-calendar enabled could inject operations: create attacker-controlled "meeting" events (the path even auto-harvests URLs from the body into the event location/description — a phishing primitive) or cancel/modify the victim's real events, with zero human in the loop. Fix: - Add core.database.get_upcoming_events(owner) and use it for the snapshot, so the LLM only ever sees the processed account owner's events. - Look up the EmailAccount owner in _auto_summarize_pass_single and pass owner= to every do_manage_calendar call, so create/update/delete are scoped to that user (owner=None stays the single-user / legacy escape hatch). - Tell the extraction model the email is untrusted data and not to follow instructions inside it (defense-in-depth against injection). Add tests/test_calendar_owner_scope.py: get_upcoming_events returns only the given owner's events (and everything when owner is None). Fails against the old unscoped query. |
||
|---|---|---|
| .. | ||
| __init__.py | ||
| admin_wipe_routes.py | ||
| api_token_routes.py | ||
| assistant_routes.py | ||
| auth_routes.py | ||
| backup_routes.py | ||
| calendar_routes.py | ||
| chat_helpers.py | ||
| chat_routes.py | ||
| cleanup_routes.py | ||
| compare_routes.py | ||
| contacts_routes.py | ||
| cookbook_helpers.py | ||
| cookbook_routes.py | ||
| diagnostics_routes.py | ||
| document_helpers.py | ||
| document_routes.py | ||
| editor_draft_routes.py | ||
| email_helpers.py | ||
| email_pollers.py | ||
| email_routes.py | ||
| embedding_routes.py | ||
| emoji_routes.py | ||
| font_routes.py | ||
| gallery_helpers.py | ||
| gallery_routes.py | ||
| history_routes.py | ||
| hwfit_routes.py | ||
| mcp_routes.py | ||
| memory_routes.py | ||
| model_routes.py | ||
| note_routes.py | ||
| personal_routes.py | ||
| prefs_routes.py | ||
| preset_routes.py | ||
| research_routes.py | ||
| search_routes.py | ||
| session_routes.py | ||
| shell_routes.py | ||
| signature_routes.py | ||
| skills_routes.py | ||
| stt_routes.py | ||
| task_routes.py | ||
| tts_routes.py | ||
| upload_routes.py | ||
| vault_routes.py | ||
| webhook_routes.py | ||