HexBrain

Shopify · Report #1044285

Removing parts of URL from jQuery request exposes links for download of Paid Digital Assets of the most recent Order placed by anyone on the store!

Validstatus
mediumseverity
$2,900bounty
58upvotes
8 Jul 2021disclosed

Summary

A report from @superbsic showed that it was possible to download the latest digital purchased order attachment for stores that have the Digital download app installed, by setting the checkout_token to be empty. The issue was that when the checkout_token was nil, we would return all orders and select the latest order from the list.

Our team immediately deployed a change to address this issue. We resolved the issue by validating the checkout_token before fetching an order.

How it was found

Please Note: I found this bug on a website made using Shopify

I tried doing the same with my Shopify store but I was not able to buy anything as it was required to add credit card details which I don't have :(

THE LINKS GIVEN AS THE EXAMPLE ARE NOT VALID LINKS BUT THE BUG WORKS ON EVERY SHOPIFY STORE THAT USES THE SAME LOGIC!!

I have blurred the name of the website where I found the bug in the images as well SO THE NAME IN THE BELOW REPORT IS CHANGED SUPERSHACKS(my store) = SOMERANDOMWEBSITE.COM(The website I tested on or every other Shopify store that makes a jQuery request to check and get the download link)

jQuery request for Downloading Digital assets exposes download link even without Checkout Id, Callback Id. Produces the Most recent order for anyone to view!!

ONCE A NEW ORDER IS PLACED, THE LINK UPDATES AUTOMATICALLY

This is bug regarding a Shopify Digital Assets/products store and probably Applies to every Digital asset/products website made with Shopify out there

this is while I was placing an order and was messing around.

Note SUPERHACKS is MYown shopify website and is not live! So replace "superhacks" with "the website you want to test"

Now when I place the order, A GET request is made for downloading the asset GET /checkout/get_download_link?callback=jQuery22009741786286098322_1606361688834&shop=superhacks.myshopify.com&checkout_token=1c0869d74100cd3582916a93a4bce741&_=1606361688835 HTTP/1.1 Host: delivery.shopifyapps.com

okay cool I Tried messing around and found out that removing everything i.e.

  • The nos. after jQuery 22009741786286098322_1606361688834
  • and even the Checkout Token!! 1c0869d74100cd3582916a93a4bce741
  • And the underscore part at the end of the URL &_=1606361688835

This is the URL (let's call it filled Link) Filled Link: https://delivery.shopifyapps.com/checkout/get_download_link?callback=jQuery22009741786286098322_1606361688834&shop=superhacks.myshopify.com&checkout_token=1c0869d74100cd3582916a93a4bce741&_=1606361688835

After removing the above mentioned part the URL looks like this (let's call it Unfilled Link) Unfilled Link: https://delivery.shopifyapps.com/checkout/get_download_link?callback=jQuery&shop=superhacks.myshopify.com&checkout_token=

In both Cases the response is the same jQuery({"ready":true,"links":[{"name":"PG000892.zip","product_name":"WILD WOLF","url":"https://superhacks.com/a/downloads/-/d6d6528fb49ed4d5/5fabe0193543d2cf","download_limit":2,"filesize":"3.07 MB"}]})

After removing these, the request still produced my order!

Same Is The Case while the CHECK ORDER REQUEST IS MADE

Filled Link: https://delivery.shopifyapps.com/checkout/check_order?callback=jQuery22009741786286098322_1606361688834&shop=superhacks.myshopify.com&checkout_token=1c0869d74100cd3582916a93a4bce741&_=1606361688835

produces this: jQuery22009741786286098322_1606361688834({"has_attachments":true,"is_downloadable":true})

Unfilled Link: https://delivery.shopifyapps.com/checkout/check_order?callback=jQuery&shop=superhacks.myshopify.com&checkout_token=

produces: jQuery({"has_attachments":true,"is_downloadable":true})

confirming there are attachements in the request made

I thought It may be due to Some cookies stored locally... BUT NO.... I tried it in incognito, Firefox, Chrome!! (Check Attached Images) It still gave the EXACT same response which is:

jQuery({"ready":true,"links":[{"name":"PG000892.zip","product_name":"WILD WOLF","url":"https://superhacks.com/a/downloads/-/d6d6528fb49ed4d5/5fabe0193543d2cf","download_limit":2,"filesize":"3.07 MB"}]})

I placed a new order and the Unfilled link's request got updated with the new order download link!!

This could lead an attacker simply getting every possible download link of the most recent order placed!!!

I think the request is not validated at the server and it stores the most recent order placed in the Unfilled link part. But this is major flaw if this logic is being used widely at every Shopify store

STEPS TO REPRODUCE::

  • Find a website that sells digital assets and is made using Shopify and uses the same default Shopify logic
  • https://delivery.shopifyapps.com/checkout/check_order?callback=jQuery&shop=**superhacks**.myshopify.com&checkout_token= REPLACE "superhacks" with THE STORE NAME YOU WANT TO TEST.
  • And That's it... whenever an order is placed, You will get the link in the following format jQuery({"ready":true,"links":[{"name":"PG000892.zip","product_name":"WILD WOLF","url":"https://superhacks.com/a/downloads/-/d6d6528fb49ed4d5/5fabe0193543d2cf","download_limit":2,"filesize":"3.07 MB"}]}) IT HAS THE DOWNLOAD LINK (URL PART)!!

SAME IS THE CASE WHEN ANY PRODUCT IS ORDERED BY ONE USER, EVERYONE CAN ACCESS/DOWNLOAD IT I tried it doing it with another product and it worked!

Thank you Regards Adarsh

Impact An attacker could achieve download links for every order placed on the website by looping the URL and the URL would produce the MOST RECENT ORDER!

Impact

Anyone Can Download/see/check the latest order placed by someone on the website....

Essentially both anyone can download the files Ordered by someone else for himself!

This report was disclosed publicly on HackerOne and belongs to its author and the program. See the original