Skip to content

fix(core): validate and 404 before touching edit_marker / edit_object payloads#916

Open
SAY-5 wants to merge 1 commit intomemeLab:developfrom
SAY-5:fix/edit-marker-object-order
Open

fix(core): validate and 404 before touching edit_marker / edit_object payloads#916
SAY-5 wants to merge 1 commit intomemeLab:developfrom
SAY-5:fix/edit-marker-object-order

Conversation

@SAY-5
Copy link
Copy Markdown

@SAY-5 SAY-5 commented Apr 18, 2026

What

Both edit_marker and edit_object in src/core/views/views.py had the same bug-shaped logic:

def edit_marker(request):
    index = request.GET.get("id", "-1")
    model = Marker.objects.get(id=index)

    model_data = {
        "source": model.source,
        ...
    }

    if not model or model.owner != Profile.objects.get(user=request.user):
        raise Http404

Three things are wrong:

  1. 500 on unknown/garbage id. Marker.objects.get(id=index) raises DoesNotExist for unknown ids and ValueError / DataError for non-numeric values. The default "-1" falls back to a DB query that returns nothing and again raises DoesNotExist. All three surface as HTTP 500.
  2. model_data built before the permission check. The dict is filled from the row's fields (source, created, author, patt, title) before we know if the requester owns the row. Today the data never escapes because Http404 is raised two lines later, but the ordering is exactly the kind that breaks the moment someone adds logging, a metric, or serialisation above the guard.
  3. if not model is dead code: .get() either returns an instance or raises, so the sentinel branch can never fire.

Fix

  • Coerce index to int first, Http404 on failure.
  • Fetch with get_object_or_404 so unknown id → 404.
  • Do the owner != request.user.profile check before building model_data.
  • Drop the dead if not model branch.

edit_object gets the same treatment (same bug in the same shape).

def edit_marker(request):
    index = request.GET.get("id", "-1")
    try:
        index = int(index)
    except (TypeError, ValueError):
        raise Http404
    model = get_object_or_404(Marker, id=index)
    if model.owner != request.user.profile:
        raise Http404
    model_data = { ... }

Matches the pattern already used by create_or_edit_exhibit and edit_artwork further down this file.

Fixes #846

… payloads

Both edit views did roughly:

    index = request.GET.get("id", "-1")
    model = Marker.objects.get(id=index)
    model_data = { ... model.source ... }
    if not model or model.owner != Profile.objects.get(user=request.user):
        raise Http404

Three things are wrong with this ordering:

  1. `Marker.objects.get(id=index)` raises DoesNotExist when the id is
     unknown (and ValueError / DataError when index is non-numeric junk
     like the default "-1" fed to PostgreSQL). Both surface as 500.
  2. `model_data = { ... }` runs before the permission check, so we
     read source/created/author/patt/title off the row even when the
     requesting user has no right to that object. Today the leak is
     narrow (nothing is returned to the response until after the
     Http404), but it's exactly the kind of ordering that bites the
     next refactor (e.g. adding logging or serialisation above the
     check).
  3. `if not model` is dead code: `.get()` either returns an instance
     or raises. The guard never fires.

Coerce index to int first, fetch via get_object_or_404, reject with
Http404 when owner != request.user.profile, and only then build the
model_data dict. Same pattern is used by create_or_edit_exhibit /
edit_artwork in this module, so the two views now match the rest.

Fixes memeLab#846

Signed-off-by: SAY-5 <SAY-5@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

edit_marker and edit_object fetch object before checking permissions, no DoesNotExist handling

1 participant