How to patch exploit that fakes dev product purchases?

  1. What do you want to achieve? Keep it simple and clear!
    I need to make a fix for an exploit that can apparently make the game think people purchased a dev product. (I do not know how this is possible)

  2. What is the issue? Include screenshots / videos if possible!
    this is an issue because it makes exploiters able to get many points in my game.


    the image is an image of the ingame points leaderboard, showing many alt accounts that gained very large amount of points one day, and that shouldn’t be possible to be obtained within such a short time (These exploiter alt accounts were already game banned by me)
    I wanna fix this exploit, it ruins the leaderboards for other players and it is very unfair.

  3. What solutions have you tried so far? Did you look for solutions on the Developer Hub?
    I haven’t seem to have found any solutions to fix this exploit

for information, I have data wiped and banned all the illegitimate players on my game that were found using the exploit.


this image is one that I found on my community server of someone potentially using the exploit, if anyone knows this exploit and how to patch it please let me know!

Can you share the relevant code?

The only way such an exploit can happen is if you have some remote from Client to Server that says “I purchased a dev product” and the Server will trust that remote. Are you listening for the purchase completion on the client? All dev product/gamepass/anything with robux should be handled entirely on the server when validating a purchase.

This might actually be a legit exploit on DevProducts since the exploit is scanning which means that it’s universal. I don’t think it uses any remote events.

EDIT: I just found the code and it’s open sourced lmao. I’ll see how they did it.

By searching on the internet, I have found this video

it seemed to contain the script, and this is what I found

  getgenv().promptpurchaserequestedv2 = MarketplaceService.PromptPurchaseRequestedV2:Connect(
                        function(...)
                            discord:Notification("Prompt Detected",
                                "If this is a UGC item, this script will attempt purchase. Please check console.",
                                "Okay!")
                            local startTime = tick()
                            t = {...}
                            local assetId = t[2]
                            local info = MarketplaceService:GetProductInfo(assetId)
                            pcall(function()
                                local starttickxd = tick()
                                local data = '{"collectibleItemId":"' .. tostring(info.CollectibleItemId) ..
                                     '","collectibleProductId":"' .. tostring(info.CollectibleProductId) ..
                                     '","expectedCurrency":1,"expectedPrice":' .. tostring(info.PriceInRobux) ..
                                     ',"idempotencyKey":"' ..
                                     tostring(game:GetService("HttpService"):GenerateGUID(false)) ..
                                     '","expectedSellerId":' .. tostring(info.Creator.Id) .. ',"expectedSellerType":"' ..
                                     tostring(info.Creator.CreatorType) ..
                                     '","expectedPurchaserType":"User","expectedPurchaserId":' ..
                                     tostring(game.Players.LocalPlayer.UserId) .. '}'
                                print(data)
                                -- setclipboard(data)
                                _post("https://apis.roblox.com/marketplace-sales/v1/item/" .. tostring(info.CollectibleItemId) .."/purchase-item", data);
                                wait();
                                local endTime = tick()
                                local duration = endTime - startTime
                                print("Bought Item! Took " .. tostring(duration) .. " seconds")
                            end)
                        end)
                    end)

i am not sure what that code does but it may be related to the exploit

To be blunt, the only reason this exploit is a thing is because people don’t read documentation.

The easiest way to fix this is to just use ProcessReceipt for your dev product purchases.

Stop using PromptPurchaseProductFinished to check that a player has finished purchasing a product (or not).

The reason why that exploit “only works on some games” is because those games in question make full use of ProcessReceipt, which does not have that vulnerability.

You should be using it anyways, it’s the most robust interface you have to properly process a purchase.

Hell, you’re literally recommended to use it by Roblox themselves:

Fires when a purchase prompt closes for a developer product. You can use this event to detect when a purchase prompt is closed, but it should not be used to process purchases; instead use MarketplaceService.ProcessReceipt.

Also this should go without saying - use ProcessReceipt on the server side.

3 Likes

One more thing, PromptGamePassPurchaseFinished also suffers from the same vulnerability, except this time you can’t use ProcessReceipt.

The fix for this isn’t too difficult either though - check whether the player does actually own the gamepass first before you give the player any benefits of the gamepass, using MarketplaceService:UserOwnsGamePassAsync().

3 Likes

Very cool I didn’t know about this