Significant-Gravitas/AutoGPT · critical · DatabaseError

Unauthorized update attempt for profile {existing_profile.id

Error message

Unauthorized update attempt for profile {existing_profile.id} by user {user_id}

What it means

Raised in update_profile when the Profile row selected for update belongs to a different userId than the authenticated user. This is an IDOR/authorization guard. Because the lookup filters by userId=user_id, reaching this branch requires the row's userId to have changed between fetch and check (race), or a code path calling update_profile with mismatched arguments — i.e. an internal invariant break, logged at error level with both profile ID and user ID. Note it is raised as DatabaseError, though NotAuthorizedError would be semantically correct.

Source

Thrown at autogpt_platform/backend/backend/api/features/store/db.py:1266

                )
                return store_model.ProfileDetails.from_db(created_profile)
            except prisma.errors.UniqueViolationError:
                # A concurrent request (or get_or_create_user) created the
                # Profile first. Re-fetch and fall through to update it with the
                # submitted data rather than failing the save.
                existing_profile = await prisma.models.Profile.prisma().find_first(
                    where={"userId": user_id}
                )
                if not existing_profile:
                    raise

        # Verify that the user is authorized to update this profile
        if existing_profile.userId != user_id:
            logger.error(
                f"Unauthorized update attempt for profile {existing_profile.id} "
                f"by user {user_id}"
            )
            raise DatabaseError(
                f"Unauthorized update attempt for profile {existing_profile.id} "
                f"by user {user_id}"
            )

        logger.debug(f"Updating existing profile for user {user_id}")
        # Prepare update data, only including non-None values
        update_data = {}
        if profile.name is not None:
            update_data["name"] = profile.name
        if profile.username is not None:
            update_data["username"] = username
        if profile.description is not None:
            update_data["description"] = profile.description
        if profile.links is not None:
            update_data["links"] = profile.links
        if profile.avatar_url is not None:
            update_data["avatarUrl"] = profile.avatar_url

View on GitHub (pinned to 9c8bb5550f)

Solutions

  1. Treat as a security-relevant incident: capture the logged profile ID and user ID pair.
  2. Inspect Profile.userId in the DB for the listed profile — if it changed unexpectedly, audit who/what changed it.
  3. If you are calling update_profile directly, ensure the user_id you pass is the authenticated user, not the profile owner parameter.
  4. Consider patching the code to raise NotAuthorizedError instead of DatabaseError so the API returns 403 rather than 500.

Example fix

# before
raise DatabaseError(f"Unauthorized update attempt for profile {existing_profile.id} by user {user_id}")
# after
from backend.util.exceptions import NotAuthorizedError
raise NotAuthorizedError(f"Unauthorized update attempt for profile {existing_profile.id}")
Defensive patterns

Strategy: try-catch

Try / catch

from backend.util.exceptions import DatabaseError

try:
    await store_db.update_profile(user_id, profile)
except DatabaseError as e:
    if 'Unauthorized update attempt' in str(e):
        security_log.alert('profile ownership race', user_id=user_id)
        raise Forbidden() from e  # surface as 403, not 500
    raise

Prevention

When it happens

Trigger: Two concurrent profile updates where one changes the row's ownership; a direct call to update_profile with a profile object whose existing row resolves to another user; data corruption where a Profile row's userId was edited mid-request.

Common situations: Almost never seen in practice from the HTTP API; observed in tests calling the service function with mismatched fixtures, or after manual DB edits to Profile.userId.

Understand the failure class

Related errors


AI-assisted analysis of Significant-Gravitas/AutoGPT@9c8bb5550f (2026-08-14). Data as JSON: /api/errors/08c329fa8a2dc0f1. Report an issue: GitHub.