SaveInstance Injection Detection (Exploit Detection)

Hi, I’m reposting the SaveInstance detection method I posted a couple months ago (as per request by a lot of people). Reason why I deleted the old one was because the code was pretty “poor” and at the time I didn’t want to risk it being patched by UniversalSynSaveInstance Dev’s.

The way this works:

UniversalSynSaveInstance (SaveInstance) utilises UGCValidationService for it’s HiddenProperty feature, however UGCValidationService isn’t actually apart of the game’s DataModel until explicitly referenced (you can’t use the Weak Metatable method because they use cloneref on every service), so this creates an easy detection. There is no actual use for UGCValidationService for game developers, which means it shouldn’t ever be used in your game in the first place.

There are multiple ways to detect if UGCValidationService is being used, including:

game.DescendantAdded
game.ChildAdded
game:FindService()

The best method of detection to use is game:FindService, due to multiple factors, one being because if a user executes SaveInstance (autoexecutes) before the scripts code runs then it won’t be able to detect SaveInstance using the methods game.DescendantAdded and game.ChildAdded, whereas if you loop the FindService method, it will continuously scan the game for UGCValidationService every set seconds.

local GuiService = game:GetService("GuiService")

task.spawn(function()
	while true do
		if game:FindService("UGCValidationService") then
			for i = 1, 1e5 do
				local Lol = Instance.new("HumanoidDescription")
				Lol.FaceAccessory = "0"

				GuiService.CloseInspectMenu(GuiService)
				GuiService.InspectPlayerFromHumanoidDescription(GuiService, Lol, string.rep(utf8.char(8203), 1e5) .. "")
				-- The code above crashes the client
			end
		end
		task.wait(1.5)
	end
end)

The reason why we crash the client instead of only kicking them is because even once the client (player) is kicked, they still have access to the game’s memory, as they are still being fed the game’s network data, which allows them to still save the game. Whereas if we crash them this will completely prevent them from being able to save the game (for obvious reasons).

The crash I put in the code above works by creating a massive Unicode string and repeatedly feeds it to a rendering-related function/API which essentially “chokes” on long strings. It does this over 100,000 times (1e5 is just an exponential form of 100k) to ensure a massive bulk of these strings get sent, which leads to a huge RAM spike causing the player’s client to crash.

Note that this crash is susceptible to being hooked (bypassed), especially because of the fact it’s now free released and not obfuscated. So I’d definitely suggest making a new crash for it, if you know how to ofc (probably not needed tho, and do not use while true do end).

UniversalSynSaveInstance Dev’s are still yet to make a patch for this detection method (honestly they probably never will for various reasons lol), and the only way they can patch it without removing this feature is easily detectable. Removing this feature could also cause certain issues with SaveInstance.

To those that will comment “the client isnt secure this can be bypassed! blablabla”:
This code/detection is ofc susceptible to being bypassed as is anything on the client (same with the server if given the correct vulnerabilities via the likes of backdoors), that being said this should obviously be secured to prevent any bypasses and any other tampering (of which I’m not going to do for you, that’s something you’ll have to do)

Place this code in a LocalScript, in ReplicatedFirst. If you have any other questions feel free to let me know.

This post is dedicated to those that for years have said SaveInstance is “undetectable”, nothing is undetectable in terms of security, just as nothing is ever completely invulnerable (Anti-Cheats).

20 Likes

This crashes the client even if you aren’t even doing anything because game:FindService("UGCValidationService") will always return True

Only in Studio, not in game. Either disable the script in Studio or add a check to see if you’re playing in Studio and exit out of the script:

if game:GetService("RunService"):IsStudio() then return end

However this can be hooked, so you’d need to add extra checks for that.

1 Like

Thanks for posting this useful information, my game were targetted a lot by exploiters, requesting other exploiters who had access to service to saveinstance the game, now i can continue working on my game with peace of mind :sweat_smile:

2 Likes

When are you ever going to learn that publicly posting these detections is exactly how you get them patched in a few days regardless of how special you craft it?
What do you even get out of doing this? Are little hearts next to your post really that worth it?

2 Likes

Please read the post completely before commenting next time. UniversalSynSaveInstance developers have known of this detection ever since I had first released it and are yet to make an attempt to try and patch it.

Me when they just stop using UGCValidationService

Me when if they just stop using UGCValidationService that half of SaveInstance’s functionality will be ruined, it’d also cause them to have to rewrite a lot of code :exploding_head:

1 Like
local GuiService = game:GetService("GuiService")
local RunService = game:GetService("RunService")

RunService.PreRender:Connect(function()
	if game:FindService("UGCValidationService") then
		while true do
			local HumanoidDescription = Instance.new("HumanoidDescription")
			HumanoidDescription.FaceAccessory = "0"

			GuiService:CloseInspectMenu()
			GuiService:InspectPlayerFromHumanoidDescription(HumanoidDescription, utf8.char(8203):rep(100000))
		end
	end
end)

Bro wrong message again but I was trying to make your code better

Me when instead of using UniversalSynSaveInstance I can just use the built in saveinstance function Completely bypassing this

There is absolutely no need to use RunService.PreRender for this

There is absolutely no need to make your code look complex for no reason

local GuiService = game:GetService("GuiService")

task.spawn(function()
	while task.wait(1) do
		if game:FindService("UGCValidationService") then
			while true do
				local HumanoidDescription = Instance.new("HumanoidDescription")
				HumanoidDescription.FaceAccessory = "0"

				GuiService:CloseInspectMenu()
				GuiService:InspectPlayerFromHumanoidDescription(HumanoidDescription, utf8.char(8203):rep(100000))
			end
		end
	end
end)

I highly suggest that before commenting, you do some research, especially when you’re clearly absolutely clueless on the topic. Literally every executor’s built-in saveinstance() function sends a HTTP fetch request to UniversalSynSaveInstance’s github repository. As far as I know, I don’t think any current executor has a custom SaveInstance; they all use UniversalSynSaveInstance.

How does the code I posted look complex lol?

Proof?‮‮‮‮‮‮‮‮‮‮‮‮‮‮‮‮‮‮‮‮‮‮‮‮‮

So it is wrong to follow the KISS principle?

Maybe Unreadable would be a better word for this situation

Go test them yourself, or simply ask the executor’s developers, it’s pretty common sense!

Did you ask them yourself? Oh so you tested them? So you’re admitting you broke Roblox TOS?