fix(multiuser): redact other users' current-item identifiers from queue status - #9087
Merged
Merged
Conversation
…ue status events
QueueItemStatusChangedEvent embeds the SessionQueueStatus, which includes the
currently-running item's item_id, session_id, and batch_id. The event ships to
user:{owner} and admin rooms. When user A's item changed status while user B's
item was the one in progress, owner A's frontend received the event with B's
identifiers exposed.
In _set_queue_item_status, scrub item_id/session_id/batch_id from the embedded
queue_status when the in-progress item belongs to a different user than the
changed item. Aggregate counts remain global (not user-sensitive).
Identified out-of-scope in the security audit of #127.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
lstein
requested review from
JPPhoto,
blessedcoolant and
dunkeroni
as code owners
April 25, 2026 19:05
JPPhoto
requested changes
Apr 29, 2026
JPPhoto
left a comment
Collaborator
There was a problem hiding this comment.
Findings
invokeai/app/services/session_queue/session_queue_sqlite.py:319:
The redaction decision is based on a secondget_current()read afterget_queue_status()has already embedded the current item's identifiers. These reads are not atomic: the DB lock is only held inside each transaction, and_set_queue_item_status()releases it betweenget_queue_status()and the newget_current()call. If user B is current when line 319 buildsqueue_status, then B completes or is canceled before line 326,current_itembecomesNoneand the stale Bitem_id,session_id, andbatch_idremain in the event sent to user A. This leaves a race-window version of the leak the PR is trying to close. To expose this issue, add a test that makes the first current-item read used byget_queue_status()return another user's in-progress item, then makes the second redaction read returnNone, and asserts the emitted event is still scrubbed.
Collaborator
Author
I've added a |
JPPhoto
self-requested a review
April 30, 2026 21:00
lstein
added a commit
that referenced
this pull request
Jun 23, 2026
…r non-admins (#9262) * fix(multiuser): restore global queue counts + redacted entries for non-admins PR #9018 changed the queue status/list endpoints from "global counts + per-user counts" to "user-scoped only" for non-admins. This silently broke two multiuser behaviors: 1. The hamburger-menu badge lost its "X/Y" form. #9018 dropped the user_pending/user_in_progress fields, made pending/in_progress/total user-scoped (so a non-admin had no global total), and reduced the badge to a single number. 2. The virtualized queue list stopped showing other users' redacted entries. #9018 added `AND user_id = ?` to get_queue_item_ids, so a non-admin only ever received their own item ids — the (intact) sanitize_queue_item_for_user redaction never ran for other users' items. Restore the original design (PR #8822) while keeping the #9087 current-item identifier redaction: - SessionQueueStatus regains optional user_pending/user_in_progress. - get_queue_status always computes GLOBAL aggregate counts and, when user_id is provided, additionally returns that user's own counts. The current item's identifiers are still gated to the owner/admin via a single get_current() snapshot (race-free, #9087 preserved). - get_queue_item_ids no longer filters by user; ids carry no sensitive data and items are redacted at hydration by sanitize_queue_item_for_user, so non-admins again see partially-redacted entries for other users' jobs. - QueueCountBadge renders "<own>/<global total>" in multiuser mode and the plain total for admins / single-user mode. - Regenerate the frontend OpenAPI schema. Aggregate counts are global but non-identifying (no session_id/batch_id/ params/graph), consistent with #9087's "counts remain global" decision. Tests: - Update the model-shape test to assert user_pending/user_in_progress exist. - Add session-queue integration tests: global counts + per-user subcounts, admin/global omission of subcounts, current-item redaction with global counts intact, and get_queue_item_ids returning every user's ids. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore(frontend): typegen + openapi * chore(backend): ruff --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Alexander Eichhorn <alex@eichhorn.dev>
dunkeroni
pushed a commit
to dunkeroni/InvokeAI
that referenced
this pull request
Jun 29, 2026
…r non-admins (invoke-ai#9262) * fix(multiuser): restore global queue counts + redacted entries for non-admins PR invoke-ai#9018 changed the queue status/list endpoints from "global counts + per-user counts" to "user-scoped only" for non-admins. This silently broke two multiuser behaviors: 1. The hamburger-menu badge lost its "X/Y" form. invoke-ai#9018 dropped the user_pending/user_in_progress fields, made pending/in_progress/total user-scoped (so a non-admin had no global total), and reduced the badge to a single number. 2. The virtualized queue list stopped showing other users' redacted entries. invoke-ai#9018 added `AND user_id = ?` to get_queue_item_ids, so a non-admin only ever received their own item ids — the (intact) sanitize_queue_item_for_user redaction never ran for other users' items. Restore the original design (PR invoke-ai#8822) while keeping the invoke-ai#9087 current-item identifier redaction: - SessionQueueStatus regains optional user_pending/user_in_progress. - get_queue_status always computes GLOBAL aggregate counts and, when user_id is provided, additionally returns that user's own counts. The current item's identifiers are still gated to the owner/admin via a single get_current() snapshot (race-free, invoke-ai#9087 preserved). - get_queue_item_ids no longer filters by user; ids carry no sensitive data and items are redacted at hydration by sanitize_queue_item_for_user, so non-admins again see partially-redacted entries for other users' jobs. - QueueCountBadge renders "<own>/<global total>" in multiuser mode and the plain total for admins / single-user mode. - Regenerate the frontend OpenAPI schema. Aggregate counts are global but non-identifying (no session_id/batch_id/ params/graph), consistent with invoke-ai#9087's "counts remain global" decision. Tests: - Update the model-shape test to assert user_pending/user_in_progress exist. - Add session-queue integration tests: global counts + per-user subcounts, admin/global omission of subcounts, current-item redaction with global counts intact, and get_queue_item_ids returning every user's ids. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore(frontend): typegen + openapi * chore(backend): ruff --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Alexander Eichhorn <alex@eichhorn.dev>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR closes a minor security hole in the multiuser implementation which allowed
item_id,session_idandbatch_ididentifiers from one user's running generation session to leak to another user.QueueItemStatusChangedEventembeds aSessionQueueStatusthat includes thecurrently-running item's
item_id,session_id, andbatch_id. The full eventships to
user:{owner}andadminrooms. When user A's item changed status whileuser B's item was the one in progress, owner A's frontend received the event with
B's identifiers exposed in the embedded
queue_status.Fix
In
_set_queue_item_status, after buildingqueue_status, scrubitem_id/session_id/batch_idwhen the in-progress item belongs to a different userthan the changed item. Aggregate counts stay global (not user-sensitive). The
frontend never reads those fields off the event payload (only
batch_status.batch_id,which is the changed item's own batch — no leak), so no UI behavior changes.
Test plan
test_event_redacts_other_users_current_item_identifiersverifies that when user B's item is in_progress and user A's item is canceled,
A's emitted event has
queue_status.item_id/session_id/batch_id == None.test_event_preserves_owner_current_item_identifiersconfirms no over-redactionwhen there's no in-progress item.
test_event_preserves_identifiers_when_current_item_is_the_changed_itemconfirmsidentifiers ARE exposed when the in-progress item is the changed item itself.