Hacktoberfest 2026: los issues que los mantenedores marcaron para octubre, abiertos y aptos para principiantes. Explorar issues de Hacktoberfest

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

Abierto
#9,534 0 comentarios 0 reacciones 1 asignado Ver en GitHub

Los mantenedores suelen responder en 5 días

@lstein ya está trabajando en esto.

Desde el 24/8/2026.

Evaluación

Este issue todavía no se ha evaluado.

Descripción

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.
Lenguaje dominante
Python
Estrellas
28.3k
Forks
3k
Merge medio
6 d 22 h
PR fusionados (30 d)
10

Preparar el entorno

  • Sin Dockerfile ni archivo de Docker Compose
  • Tiene una plantilla de pull request
  • Sin guía de contribución

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de invoke-ai/InvokeAI

Todos los issues de invoke-ai/InvokeAI

Issues similares

Más issues de Python

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.