VYPR
Medium severity5.3OSV Advisory· Published Sep 9, 2025· Updated Apr 15, 2026

CVE-2025-58442

CVE-2025-58442

Description

Saleor is an e-commerce platform. Starting in version 3.21.0 and prior to version 3.21.16, requesting certain fields in the response of accountRegister may result in errors that could unintentionally reveal whether a user with the provided email already exists in Saleor. Version 3.21.16 fixes the issue. As a workaround, rate-limit the mutation to reduce the impact.

Affected products

1

Patches

2
09d671e91ea5

Merge commit from fork

https://github.com/saleor/saleorMaciej KorycinskiSep 9, 2025via osv
9 files changed · +156 33
  • package.json+1 1 modified
    @@ -1,6 +1,6 @@
     {
       "name": "saleor",
    -  "version": "3.21.15",
    +  "version": "3.21.16",
       "engines": {
         "node": ">=16 <17",
         "npm": ">=7"
    
  • package-lock.json+2 2 modified
    @@ -1,12 +1,12 @@
     {
       "name": "saleor",
    -  "version": "3.21.15",
    +  "version": "3.21.16",
       "lockfileVersion": 2,
       "requires": true,
       "packages": {
         "": {
           "name": "saleor",
    -      "version": "3.21.15",
    +      "version": "3.21.16",
           "license": "BSD-3-Clause",
           "devDependencies": {
             "@release-it/bumper": "^4.0.0",
    
  • pyproject.toml+1 1 modified
    @@ -53,7 +53,7 @@ help = "Run tests with db reuse to speed up testing time"
     
     [tool.poetry]
     name = "saleor"
    -version = "3.21.15"
    +version = "3.21.16"
     description = "A modular, high performance, headless e-commerce platform built with Python, GraphQL, Django, and React."
     authors = [ "Saleor Commerce <hello@saleor.io>" ]
     license = "BSD-3-Clause"
    
  • saleor/account/models.py+1 1 modified
    @@ -191,7 +191,7 @@ class User(
         uuid = models.UUIDField(default=uuid4, unique=True)
     
         USERNAME_FIELD = "email"
    -    RETURN_ID_IN_API_RESPONSE = True
    +    NEWLY_CREATED_USER = False
     
         objects = UserManager()
     
    
  • saleor/graphql/account/mutations/account/account_register.py+3 1 modified
    @@ -102,7 +102,7 @@ def mutate(cls, root, info: ResolveInfo, **data):
             )
             # we don't want to return id's as it will allow to deduce if user exists
             if response.user:
    -            response.user.RETURN_ID_IN_API_RESPONSE = False
    +            response.user.NEWLY_CREATED_USER = True
             return response
     
         @classmethod
    @@ -187,6 +187,8 @@ def perform_mutation(cls, _root, info: ResolveInfo, /, **data):
             context_data = RequestorAwareContext.create_context_data(info.context)
             cls.save_and_create_task(user_exists, instance, cleaned_input, context_data)
     
    +        # Sets updated_at, to always return the time when mutation was called
    +        instance.updated_at = instance.date_joined
             return cls.success_response(instance)
     
         @classmethod
    
  • saleor/graphql/account/tests/mutations/account/test_account_register.py+86 20 modified
    @@ -2,6 +2,8 @@
     from urllib.parse import urlencode
     
     from django.test import override_settings
    +from django.utils import timezone
    +from freezegun import freeze_time
     
     from ......account import events as account_events
     from ......account.models import User
    @@ -16,25 +18,77 @@
     from .....tests.utils import get_graphql_content
     
     ACCOUNT_REGISTER_MUTATION = """
    -    mutation RegisterAccount(
    -        $input: AccountRegisterInput!
    -    ) {
    -        accountRegister(
    -            input: $input
    -        ) {
    -            errors {
    -                field
    -                message
    -                code
    -            }
    -            user {
    -                id
    -                email
    -                firstName
    -                lastName
    -            }
    +mutation RegisterAccount($input: AccountRegisterInput!) {
    +  accountRegister(input: $input) {
    +    errors {
    +      field
    +      message
    +      code
    +    }
    +    user {
    +      id
    +      email
    +      firstName
    +      lastName
    +      addresses {
    +        streetAddress1
    +      }
    +      metadata {
    +        key
    +      }
    +      metafield(key: "test")
    +      metafields(keys: ["test1"])
    +      checkoutIds
    +      checkouts(first: 10) {
    +        edges {
    +          node {
    +            id
    +          }
    +        }
    +      }
    +      giftCards(first: 1) {
    +        edges {
    +          node {
    +            id
    +          }
             }
    +      }
    +      orders(first: 1) {
    +        edges {
    +          node {
    +            id
    +          }
    +        }
    +      }
    +      userPermissions {
    +        code
    +      }
    +      storedPaymentMethods(channel: "default-channel") {
    +        id
    +      }
    +      dateJoined
    +      lastLogin
    +      externalReference
    +      defaultBillingAddress {
    +        id
    +      }
    +      defaultShippingAddress {
    +        id
    +      }
    +      languageCode
    +      storedPaymentSources {
    +        __typename
    +      }
    +      avatar {
    +        url
    +      }
    +      isStaff
    +      isActive
    +      isConfirmed
    +      updatedAt
         }
    +  }
    +}
     """
     
     
    @@ -165,6 +219,8 @@ def test_customer_register_twice(
         data = content["data"][mutation_name]
         params = urlencode({"email": email, "token": "token"})
         confirm_url = prepare_url(params, redirect_url)
    +    new_user.last_login = timezone.now()
    +    new_user.save()
     
         expected_payload = {
             "user": get_default_user_payload(new_user),
    @@ -201,18 +257,28 @@ def test_customer_register_twice(
         # remove personal data from input
         del variables["input"]["firstName"]
         del variables["input"]["lastName"]
    -    response = api_client.post_graphql(query, variables)
    -    content = get_graphql_content(response)
    -    data = content["data"][mutation_name]
    +    with freeze_time("2025-06-01 12:00:01"):
    +        query_time = timezone.now()
    +        response = api_client.post_graphql(query, variables)
    +        content = get_graphql_content(response)
    +        data = content["data"][mutation_name]
     
         # then
         assert not data["errors"]
     
    +    new_user.refresh_from_db()
    +    assert new_user.updated_at != query_time
    +    assert new_user.date_joined != query_time
    +    assert new_user.last_login is not None
    +
         customer_creation_event = account_events.CustomerEvent.objects.get()
         assert data["user"]["firstName"] == ""
         assert data["user"]["lastName"] == ""
         assert data["user"]["email"] == variables["input"]["email"]
         assert data["user"]["id"] == ""
    +    assert data["user"]["updatedAt"] == query_time.isoformat()
    +    assert data["user"]["dateJoined"] == query_time.isoformat()
    +    assert data["user"]["lastLogin"] is None
         assert customer_creation_event.type == account_events.CustomerEvents.ACCOUNT_CREATED
         assert customer_creation_event.user == new_user
         assert mocked_finish_creating_user.delay.call_count == 2
    
  • saleor/graphql/account/types.py+60 2 modified
    @@ -329,6 +329,19 @@ def resolve_source_permission_groups(root: Permission, info: ResolveInfo, user_i
             return groups
     
     
    +def is_newly_created_user(
    +    user: models.User,
    +):
    +    """Determine if the resolver is called for newly created user.
    +
    +    Newly created user can be represented as user instance that is not stored in DB.
    +    We need to skip any resolvers that requires existing id value.
    +    """
    +    if getattr(user, "NEWLY_CREATED_USER", False):
    +        return True
    +    return False
    +
    +
     @federated_entity("id")
     @federated_entity("email")
     class User(ModelObjectType[models.User]):
    @@ -492,10 +505,14 @@ class Meta:
     
         @staticmethod
         def resolve_addresses(root: models.User, _info: ResolveInfo):
    +        if is_newly_created_user(root):
    +            return []
             return root.addresses.annotate_default(root).all()
     
         @staticmethod
         def resolve_checkout(root: models.User, info: ResolveInfo):
    +        if is_newly_created_user(root):
    +            return []
             database_connection_name = get_database_connection_name(info.context)
             checkout = get_user_checkout(
                 root, database_connection_name=database_connection_name
    @@ -507,6 +524,9 @@ def resolve_checkout(root: models.User, info: ResolveInfo):
         @staticmethod
         @traced_resolver
         def resolve_checkout_tokens(root: models.User, info: ResolveInfo, channel=None):
    +        if is_newly_created_user(root):
    +            return []
    +
             def return_checkout_tokens(checkouts):
                 if not checkouts:
                     return []
    @@ -530,6 +550,9 @@ def return_checkout_tokens(checkouts):
         @staticmethod
         @traced_resolver
         def resolve_checkout_ids(root: models.User, info: ResolveInfo, channel=None):
    +        if is_newly_created_user(root):
    +            return []
    +
             def return_checkout_ids(checkouts):
                 if not checkouts:
                     return []
    @@ -561,6 +584,9 @@ def _resolve_checkouts(checkouts):
                     allow_sync_webhooks=False,
                 )
     
    +        if is_newly_created_user(root):
    +            return _resolve_checkouts([])
    +
             if channel := kwargs.get("channel"):
                 return (
                     CheckoutByUserAndChannelLoader(info.context)
    @@ -578,33 +604,46 @@ def _resolve_gift_cards(gift_cards):
                     gift_cards, info, kwargs, GiftCardCountableConnection
                 )
     
    +        if is_newly_created_user(root):
    +            return _resolve_gift_cards([])
    +
             return (
                 GiftCardsByUserLoader(info.context).load(root.id).then(_resolve_gift_cards)
             )
     
         @staticmethod
         def resolve_user_permissions(root: models.User, info: ResolveInfo):
    +        if is_newly_created_user(root):
    +            return []
             from .resolvers import resolve_permissions
     
             return resolve_permissions(root, info)
     
         @staticmethod
         def resolve_permission_groups(root: models.User, info: ResolveInfo):
    +        if is_newly_created_user(root):
    +            return []
             return root.groups.using(get_database_connection_name(info.context)).all()
     
         @staticmethod
         def resolve_editable_groups(root: models.User, info: ResolveInfo):
    +        if is_newly_created_user(root):
    +            return []
             database_connection_name = get_database_connection_name(info.context)
             return get_groups_which_user_can_manage(root, database_connection_name)
     
         @staticmethod
    -    def resolve_accessible_channels(root: models.Group, info: ResolveInfo):
    +    def resolve_accessible_channels(root: models.User, info: ResolveInfo):
    +        if is_newly_created_user(root):
    +            return []
             # Sum of channels from all user groups. If at least one group has
             # `restrictedAccessToChannels` set to False - all channels are returned
             return AccessibleChannelsByUserIdLoader(info.context).load(root.id)
     
         @staticmethod
    -    def resolve_restricted_access_to_channels(root: models.Group, info: ResolveInfo):
    +    def resolve_restricted_access_to_channels(root: models.User, info: ResolveInfo):
    +        if is_newly_created_user(root):
    +            return False
             # Returns False if at least one user group has `restrictedAccessToChannels`
             # set to False
             return RestrictedChannelAccessByUserIdLoader(info.context).load(root.id)
    @@ -615,12 +654,23 @@ def resolve_note(root: models.User, _info: ResolveInfo):
     
         @staticmethod
         def resolve_events(root: models.User, info: ResolveInfo):
    +        if is_newly_created_user(root):
    +            return []
             return CustomerEventsByUserLoader(info.context).load(root.id)
     
         @staticmethod
         def resolve_orders(root: models.User, info: ResolveInfo, **kwargs):
             from ..order.types import OrderCountableConnection
     
    +        if is_newly_created_user(root):
    +            return create_connection_slice_for_sync_webhook_control_context(
    +                [],
    +                info,
    +                kwargs,
    +                OrderCountableConnection,
    +                allow_sync_webhooks=False,
    +            )
    +
             user_or_app = get_user_or_app_from_context(info.context)
             if not user_or_app or (
                 root != user_or_app
    @@ -699,6 +749,8 @@ def _resolve_avatar(thumbnail):
         def resolve_stored_payment_sources(
             root: models.User, info: ResolveInfo, channel=None
         ):
    +        if is_newly_created_user(root):
    +            return []
             from .resolvers import resolve_payment_sources
     
             if root == info.context.user:
    @@ -743,6 +795,8 @@ def resolve_stored_payment_methods(
             info: ResolveInfo,
             channel: str,
         ):
    +        if is_newly_created_user(root):
    +            return []
             requestor = get_user_or_app_from_context(info.context)
             if not requestor or requestor.id != root.id:
                 return []
    @@ -764,12 +818,16 @@ def get_stored_payment_methods(data: tuple[Channel, "PluginsManager"]):
     
         @staticmethod
         def resolve_default_billing_address(root: models.User, info: ResolveInfo):
    +        if is_newly_created_user(root):
    +            return None
             if root.default_billing_address_id:
                 return AddressByIdLoader(info.context).load(root.default_billing_address_id)
             return None
     
         @staticmethod
         def resolve_default_shipping_address(root: models.User, info: ResolveInfo):
    +        if is_newly_created_user(root):
    +            return None
             if root.default_shipping_address_id:
                 return AddressByIdLoader(info.context).load(
                     root.default_shipping_address_id
    
  • saleor/graphql/core/types/common.py+1 4 modified
    @@ -117,10 +117,7 @@ def __init__(self, of_type, *args, **kwargs):
     class SecureGlobalID(graphene.GlobalID):
         @staticmethod
         def id_resolver(parent_resolver, node, root, info, parent_type_name=None, **args):
    -        if (
    -            hasattr(root, "RETURN_ID_IN_API_RESPONSE")
    -            and not root.RETURN_ID_IN_API_RESPONSE
    -        ):
    +        if hasattr(root, "NEWLY_CREATED_USER") and root.NEWLY_CREATED_USER:
                 return ""
             return graphene.GlobalID.id_resolver(
                 parent_resolver, node, root, info, parent_type_name, **args
    
  • saleor/__init__.py+1 1 modified
    @@ -3,7 +3,7 @@
     from .celeryconf import app as celery_app
     
     __all__ = ["celery_app"]
    -__version__ = "3.21.15"
    +__version__ = "3.21.16"
     
     
     class PatchedSubscriberExecutionContext:
    
b35783838e51

Merge commit from fork

https://github.com/saleor/saleorMaciej KorycinskiSep 9, 2025via osv
5 files changed · +151 28
  • saleor/account/models.py+1 1 modified
    @@ -198,7 +198,7 @@ class User(
         number_of_orders = models.PositiveIntegerField(default=0, db_default=0)
     
         USERNAME_FIELD = "email"
    -    RETURN_ID_IN_API_RESPONSE = True
    +    NEWLY_CREATED_USER = False
     
         objects = UserManager()
     
    
  • saleor/graphql/account/mutations/account/account_register.py+3 1 modified
    @@ -102,7 +102,7 @@ def mutate(cls, root, info: ResolveInfo, **data):
             )
             # we don't want to return id's as it will allow to deduce if user exists
             if response.user:
    -            response.user.RETURN_ID_IN_API_RESPONSE = False
    +            response.user.NEWLY_CREATED_USER = True
             return response
     
         @classmethod
    @@ -187,6 +187,8 @@ def perform_mutation(cls, _root, info: ResolveInfo, /, **data):
             context_data = RequestorAwareContext.create_context_data(info.context)
             cls.save_and_create_task(user_exists, instance, cleaned_input, context_data)
     
    +        # Sets updated_at, to always return the time when mutation was called
    +        instance.updated_at = instance.date_joined
             return cls.success_response(instance)
     
         @classmethod
    
  • saleor/graphql/account/tests/mutations/account/test_account_register.py+86 20 modified
    @@ -2,6 +2,8 @@
     from urllib.parse import urlencode
     
     from django.test import override_settings
    +from django.utils import timezone
    +from freezegun import freeze_time
     
     from ......account import events as account_events
     from ......account.models import User
    @@ -16,25 +18,77 @@
     from .....tests.utils import get_graphql_content
     
     ACCOUNT_REGISTER_MUTATION = """
    -    mutation RegisterAccount(
    -        $input: AccountRegisterInput!
    -    ) {
    -        accountRegister(
    -            input: $input
    -        ) {
    -            errors {
    -                field
    -                message
    -                code
    -            }
    -            user {
    -                id
    -                email
    -                firstName
    -                lastName
    -            }
    +mutation RegisterAccount($input: AccountRegisterInput!) {
    +  accountRegister(input: $input) {
    +    errors {
    +      field
    +      message
    +      code
    +    }
    +    user {
    +      id
    +      email
    +      firstName
    +      lastName
    +      addresses {
    +        streetAddress1
    +      }
    +      metadata {
    +        key
    +      }
    +      metafield(key: "test")
    +      metafields(keys: ["test1"])
    +      checkoutIds
    +      checkouts(first: 10) {
    +        edges {
    +          node {
    +            id
    +          }
    +        }
    +      }
    +      giftCards(first: 1) {
    +        edges {
    +          node {
    +            id
    +          }
             }
    +      }
    +      orders(first: 1) {
    +        edges {
    +          node {
    +            id
    +          }
    +        }
    +      }
    +      userPermissions {
    +        code
    +      }
    +      storedPaymentMethods(channel: "default-channel") {
    +        id
    +      }
    +      dateJoined
    +      lastLogin
    +      externalReference
    +      defaultBillingAddress {
    +        id
    +      }
    +      defaultShippingAddress {
    +        id
    +      }
    +      languageCode
    +      storedPaymentSources {
    +        __typename
    +      }
    +      avatar {
    +        url
    +      }
    +      isStaff
    +      isActive
    +      isConfirmed
    +      updatedAt
         }
    +  }
    +}
     """
     
     
    @@ -165,6 +219,8 @@ def test_customer_register_twice(
         data = content["data"][mutation_name]
         params = urlencode({"email": email, "token": "token"})
         confirm_url = prepare_url(params, redirect_url)
    +    new_user.last_login = timezone.now()
    +    new_user.save()
     
         expected_payload = {
             "user": get_default_user_payload(new_user),
    @@ -201,18 +257,28 @@ def test_customer_register_twice(
         # remove personal data from input
         del variables["input"]["firstName"]
         del variables["input"]["lastName"]
    -    response = api_client.post_graphql(query, variables)
    -    content = get_graphql_content(response)
    -    data = content["data"][mutation_name]
    +    with freeze_time("2025-06-01 12:00:01"):
    +        query_time = timezone.now()
    +        response = api_client.post_graphql(query, variables)
    +        content = get_graphql_content(response)
    +        data = content["data"][mutation_name]
     
         # then
         assert not data["errors"]
     
    +    new_user.refresh_from_db()
    +    assert new_user.updated_at != query_time
    +    assert new_user.date_joined != query_time
    +    assert new_user.last_login is not None
    +
         customer_creation_event = account_events.CustomerEvent.objects.get()
         assert data["user"]["firstName"] == ""
         assert data["user"]["lastName"] == ""
         assert data["user"]["email"] == variables["input"]["email"]
         assert data["user"]["id"] == ""
    +    assert data["user"]["updatedAt"] == query_time.isoformat()
    +    assert data["user"]["dateJoined"] == query_time.isoformat()
    +    assert data["user"]["lastLogin"] is None
         assert customer_creation_event.type == account_events.CustomerEvents.ACCOUNT_CREATED
         assert customer_creation_event.user == new_user
         assert mocked_finish_creating_user.delay.call_count == 2
    
  • saleor/graphql/account/types.py+60 2 modified
    @@ -329,6 +329,19 @@ def resolve_source_permission_groups(root: Permission, info: ResolveInfo, user_i
             return groups
     
     
    +def is_newly_created_user(
    +    user: models.User,
    +):
    +    """Determine if the resolver is called for newly created user.
    +
    +    Newly created user can be represented as user instance that is not stored in DB.
    +    We need to skip any resolvers that requires existing id value.
    +    """
    +    if getattr(user, "NEWLY_CREATED_USER", False):
    +        return True
    +    return False
    +
    +
     @federated_entity("id")
     @federated_entity("email")
     class User(ModelObjectType[models.User]):
    @@ -492,10 +505,14 @@ class Meta:
     
         @staticmethod
         def resolve_addresses(root: models.User, _info: ResolveInfo):
    +        if is_newly_created_user(root):
    +            return []
             return root.addresses.annotate_default(root).all()
     
         @staticmethod
         def resolve_checkout(root: models.User, info: ResolveInfo):
    +        if is_newly_created_user(root):
    +            return []
             database_connection_name = get_database_connection_name(info.context)
             checkout = get_user_checkout(
                 root, database_connection_name=database_connection_name
    @@ -507,6 +524,9 @@ def resolve_checkout(root: models.User, info: ResolveInfo):
         @staticmethod
         @traced_resolver
         def resolve_checkout_tokens(root: models.User, info: ResolveInfo, channel=None):
    +        if is_newly_created_user(root):
    +            return []
    +
             def return_checkout_tokens(checkouts):
                 if not checkouts:
                     return []
    @@ -530,6 +550,9 @@ def return_checkout_tokens(checkouts):
         @staticmethod
         @traced_resolver
         def resolve_checkout_ids(root: models.User, info: ResolveInfo, channel=None):
    +        if is_newly_created_user(root):
    +            return []
    +
             def return_checkout_ids(checkouts):
                 if not checkouts:
                     return []
    @@ -561,6 +584,9 @@ def _resolve_checkouts(checkouts):
                     allow_sync_webhooks=False,
                 )
     
    +        if is_newly_created_user(root):
    +            return _resolve_checkouts([])
    +
             if channel := kwargs.get("channel"):
                 return (
                     CheckoutByUserAndChannelLoader(info.context)
    @@ -578,33 +604,46 @@ def _resolve_gift_cards(gift_cards):
                     gift_cards, info, kwargs, GiftCardCountableConnection
                 )
     
    +        if is_newly_created_user(root):
    +            return _resolve_gift_cards([])
    +
             return (
                 GiftCardsByUserLoader(info.context).load(root.id).then(_resolve_gift_cards)
             )
     
         @staticmethod
         def resolve_user_permissions(root: models.User, info: ResolveInfo):
    +        if is_newly_created_user(root):
    +            return []
             from .resolvers import resolve_permissions
     
             return resolve_permissions(root, info)
     
         @staticmethod
         def resolve_permission_groups(root: models.User, info: ResolveInfo):
    +        if is_newly_created_user(root):
    +            return []
             return root.groups.using(get_database_connection_name(info.context)).all()
     
         @staticmethod
         def resolve_editable_groups(root: models.User, info: ResolveInfo):
    +        if is_newly_created_user(root):
    +            return []
             database_connection_name = get_database_connection_name(info.context)
             return get_groups_which_user_can_manage(root, database_connection_name)
     
         @staticmethod
    -    def resolve_accessible_channels(root: models.Group, info: ResolveInfo):
    +    def resolve_accessible_channels(root: models.User, info: ResolveInfo):
    +        if is_newly_created_user(root):
    +            return []
             # Sum of channels from all user groups. If at least one group has
             # `restrictedAccessToChannels` set to False - all channels are returned
             return AccessibleChannelsByUserIdLoader(info.context).load(root.id)
     
         @staticmethod
    -    def resolve_restricted_access_to_channels(root: models.Group, info: ResolveInfo):
    +    def resolve_restricted_access_to_channels(root: models.User, info: ResolveInfo):
    +        if is_newly_created_user(root):
    +            return False
             # Returns False if at least one user group has `restrictedAccessToChannels`
             # set to False
             return RestrictedChannelAccessByUserIdLoader(info.context).load(root.id)
    @@ -615,12 +654,23 @@ def resolve_note(root: models.User, _info: ResolveInfo):
     
         @staticmethod
         def resolve_events(root: models.User, info: ResolveInfo):
    +        if is_newly_created_user(root):
    +            return []
             return CustomerEventsByUserLoader(info.context).load(root.id)
     
         @staticmethod
         def resolve_orders(root: models.User, info: ResolveInfo, **kwargs):
             from ..order.types import OrderCountableConnection
     
    +        if is_newly_created_user(root):
    +            return create_connection_slice_for_sync_webhook_control_context(
    +                [],
    +                info,
    +                kwargs,
    +                OrderCountableConnection,
    +                allow_sync_webhooks=False,
    +            )
    +
             user_or_app = get_user_or_app_from_context(info.context)
             if not user_or_app or (
                 root != user_or_app
    @@ -699,6 +749,8 @@ def _resolve_avatar(thumbnail):
         def resolve_stored_payment_sources(
             root: models.User, info: ResolveInfo, channel=None
         ):
    +        if is_newly_created_user(root):
    +            return []
             from .resolvers import resolve_payment_sources
     
             if root == info.context.user:
    @@ -743,6 +795,8 @@ def resolve_stored_payment_methods(
             info: ResolveInfo,
             channel: str,
         ):
    +        if is_newly_created_user(root):
    +            return []
             requestor = get_user_or_app_from_context(info.context)
             if not requestor or requestor.id != root.id:
                 return []
    @@ -764,12 +818,16 @@ def get_stored_payment_methods(data: tuple[Channel, "PluginsManager"]):
     
         @staticmethod
         def resolve_default_billing_address(root: models.User, info: ResolveInfo):
    +        if is_newly_created_user(root):
    +            return None
             if root.default_billing_address_id:
                 return AddressByIdLoader(info.context).load(root.default_billing_address_id)
             return None
     
         @staticmethod
         def resolve_default_shipping_address(root: models.User, info: ResolveInfo):
    +        if is_newly_created_user(root):
    +            return None
             if root.default_shipping_address_id:
                 return AddressByIdLoader(info.context).load(
                     root.default_shipping_address_id
    
  • saleor/graphql/core/types/common.py+1 4 modified
    @@ -117,10 +117,7 @@ def __init__(self, of_type, *args, **kwargs):
     class SecureGlobalID(graphene.GlobalID):
         @staticmethod
         def id_resolver(parent_resolver, node, root, info, parent_type_name=None, **args):
    -        if (
    -            hasattr(root, "RETURN_ID_IN_API_RESPONSE")
    -            and not root.RETURN_ID_IN_API_RESPONSE
    -        ):
    +        if hasattr(root, "NEWLY_CREATED_USER") and root.NEWLY_CREATED_USER:
                 return ""
             return graphene.GlobalID.id_resolver(
                 parent_resolver, node, root, info, parent_type_name, **args
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

4

News mentions

0

No linked articles in our index yet.