Per-image mutation routes authorize and write in separate statements, so a revoked permission still applies
I maintainer di solito rispondono entro 5 giorni
@lstein ci sta già lavorando.
Dal 24/8/2026.
Valutazione
Questa issue non è ancora stata valutata.
Descrizione
Every per-image mutation route authorizes and then writes as two separate statements, so a permission that is revoked in between is applied anyway:
_assert_image_owner(image_name, current_user) # decision
ApiDependencies.invoker.services.images.update(...) # write, under a decision that may be stale
The window is small but it is a real check-then-act: between the two statements a board can flip from Public to Private, an image can be reassigned to a board the caller cannot write to, or the caller's access to the board can be withdrawn. The write still lands.
What is already conditional
#9394 closed the one instance where the race caused incorrect data movement rather than merely a late-by-microseconds mutation. board_image_records.remove_image_from_board scopes its DELETE to the board the caller was authorized against:
DELETE FROM board_images WHERE image_name = ? AND board_id = ?;
An unscoped delete followed the image if it moved between the authorization and the write, applying a decision taken about one board to a different one. The scoped form matches zero rows instead, and the route classifies the zero-row outcome (moved / already uncategorized / deleted) rather than reporting a success that did not happen.
The remaining routes — star, unstar, add-to-board — have no equivalent. Their worst case is a mutation applied under a decision that was true a moment earlier, which is why this is a follow-up and not a blocker on that PR.
Why the obvious fix does not fit
Encoding the authorization as a WHERE clause means encoding all of it, and it is a four-way disjunction spanning three tables (invokeai/app/api/routers/_access.py):
- the caller is an admin (
users.is_admin), or - the caller owns the image (
images.user_id), or - the caller owns the board the image sits on (
board_images→boards.user_id), or - that board is Public (
boards.board_visibility).
Writing that as a correlated subquery on every mutating statement duplicates the policy in SQL, in several places, with no mechanism keeping the copies in step with the Python one. The first divergence is a silent authorization bug.
The shape that would work
Move the decision into the service call, so authorization and mutation share one transaction and one policy implementation:
- a single
authorize_image_mutation(image_name, user)used by the service layer inside the transaction that performs the write, rather than by each route beforehand; - routes keep reporting per-name outcomes exactly as they do now (
failed_imagesfor a genuine failure, silent skip for a name the caller may not touch), so the API contract does not change; - storage errors keep propagating rather than being read as "denied" (the invariant #9394 established).
This is the same refactor already wanted for the last-admin guards, which have the identical check-then-act shape in UserService. Worth doing once, for both.
Not urgent because
- The mutations at risk (star, unstar, board add) are low-impact and visible to the user who performed them.
- The high-impact case — a delete or a board move landing on the wrong board — is already conditional.
- Any fix touches the service interfaces for images, boards and users together, which is a poor fit for a bug-fix PR.
- Lingua principale
- Python
- Stelle
- 28.3k
- Fork
- 3k
- Merge medio
- 6g 3h
- PR unite (30g)
- 9
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Ha un modello di pull request
- Nessuna guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di invoke-ai/InvokeAI
-
bug
Difficoltà 3/5 1-2 giorni Idoneità per principianti 68/100
I maintainer di solito rispondono entro 5 giorni
-
[enhancement]: UpscalingApertaenhancement
Difficoltà 5/5 Più di una settimana Idoneità per principianti 35/100
invoke-ai/InvokeAI#9608 · 3 commenti ·
I maintainer di solito rispondono entro 5 giorni
-
[bug]: Align Graph.add_edge and validate_self collector type validationForse già presa @JPPhoto l’ha presa 5 giorni fa. Apertabug
invoke-ai/InvokeAI#9610 · 1 assegnatario ·
I maintainer di solito rispondono entro 5 giorni
-
[bug]: Nested Iterate execution mixes values across outer iterationsForse già presa @JPPhoto l’ha presa 5 giorni fa. Apertabug
invoke-ai/InvokeAI#9609 · 1 assegnatario ·
I maintainer di solito rispondono entro 5 giorni
-
enhancement
Difficoltà 5/5 Più di una settimana Idoneità per principianti 35/100
I maintainer di solito rispondono entro 5 giorni
Tutte le issue di invoke-ai/InvokeAI
Issue simili
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 88/100
BasedHardware/omi#20271 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 92/100
openai/openai-cookbook#3153 ·
I maintainer di solito rispondono entro 1 giorno
-
cvss-severity:high devguard l3montree-cybersecurity/devguard/devguard pkg:golang/github.com/l3montree-dev/devguard risk:low state:open
Difficoltà 2/5 1-3 ore Idoneità per principianti 65/100
l3montree-dev/devguard#3146 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
-
bug confirmed issue
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
open-webui/open-webui#31849 · 2 commenti ·
I maintainer di solito rispondono entro 1 giorno