ulysses/routes
Collin 70a71f603c
Scope email calendar extraction to account owner
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.
2026-06-01 23:12:32 +09:00
..
__init__.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
admin_wipe_routes.py Add native Windows compatibility layer 2026-06-01 15:09:47 +09:00
api_token_routes.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
assistant_routes.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
auth_routes.py Run auth password work off the event loop 2026-06-01 23:12:12 +09:00
backup_routes.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
calendar_routes.py Fix YEARLY recurring CalDAV events only showing on DTSTART year (#179) 2026-06-01 13:42:44 +09:00
chat_helpers.py feat(ai): add OpenRouter and Ollama Cloud providers (#231) 2026-06-01 14:26:10 +09:00
chat_routes.py Add SSRF-guarded web fetch agent tool 2026-06-01 16:57:28 +09:00
cleanup_routes.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
compare_routes.py feat(ai): add OpenRouter and Ollama Cloud providers (#231) 2026-06-01 14:26:10 +09:00
contacts_routes.py Add native Windows compatibility layer 2026-06-01 15:09:47 +09:00
cookbook_helpers.py Allow serving cached local llama.cpp models 2026-06-01 23:10:08 +09:00
cookbook_routes.py Allow serving cached local llama.cpp models 2026-06-01 23:10:08 +09:00
diagnostics_routes.py Fix email-thread HTML injection, attachment path traversal, and missing authz (#475) 2026-06-01 22:20:17 +09:00
document_helpers.py Harden PDF document markers against cross-owner upload access (#445) 2026-06-01 22:38:14 +09:00
document_routes.py Harden PDF document markers against cross-owner upload access (#445) 2026-06-01 22:38:14 +09:00
editor_draft_routes.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
email_helpers.py Fix email-thread HTML injection, attachment path traversal, and missing authz (#475) 2026-06-01 22:20:17 +09:00
email_pollers.py Scope email calendar extraction to account owner 2026-06-01 23:12:32 +09:00
email_routes.py Fix email-thread HTML injection, attachment path traversal, and missing authz (#475) 2026-06-01 22:20:17 +09:00
embedding_routes.py Add native Windows compatibility layer 2026-06-01 15:09:47 +09:00
emoji_routes.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
font_routes.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
gallery_helpers.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
gallery_routes.py Gate image editor AI endpoints by privilege (#447) 2026-06-01 22:35:24 +09:00
history_routes.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
hwfit_routes.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
mcp_routes.py Fix email-thread HTML injection, attachment path traversal, and missing authz (#475) 2026-06-01 22:20:17 +09:00
memory_routes.py feat: allow memory import without session (#493) 2026-06-01 22:32:17 +09:00
model_routes.py fix: clear session headers on endpoint deletion (#477) 2026-06-01 22:19:54 +09:00
note_routes.py Add native Windows compatibility layer 2026-06-01 15:09:47 +09:00
personal_routes.py Scope personal RAG uploads by owner (#446) 2026-06-01 22:36:53 +09:00
prefs_routes.py Add native Windows compatibility layer 2026-06-01 15:09:47 +09:00
preset_routes.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
research_routes.py Add native Windows compatibility layer 2026-06-01 15:09:47 +09:00
search_routes.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
session_routes.py Fix email-thread HTML injection, attachment path traversal, and missing authz (#475) 2026-06-01 22:20:17 +09:00
shell_routes.py Harden Cookbook package SSH probe 2026-06-01 22:44:34 +09:00
signature_routes.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
skills_routes.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
stt_routes.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
task_routes.py Polish email tasks and window controls 2026-06-01 20:56:46 +09:00
tts_routes.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
upload_routes.py Add native Windows compatibility layer 2026-06-01 15:09:47 +09:00
vault_routes.py Add native Windows compatibility layer 2026-06-01 15:09:47 +09:00
webhook_routes.py feat(ai): add OpenRouter and Ollama Cloud providers (#231) 2026-06-01 14:26:10 +09:00