Hacktoberfest 2026: le issue che i maintainer hanno segnato per ottobre, aperte e adatte ai principianti. Sfoglia le issue Hacktoberfest

Per-image mutation routes authorize and write in separate statements, so a revoked permission still applies

Aperta
#9,534 0 commenti 0 reazioni 1 assegnatario Vedi su GitHub

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_images for 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

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di invoke-ai/InvokeAI

Tutte le issue di invoke-ai/InvokeAI

Issue simili

Altre issue su Python

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.