Patching rawset to prevent exploiters from changing ModuleScript tables?

Just found out that exploiters can use rawset and rawget to both fetch and change a modulescript table leaving it vulnerable to some game breaking mechanics (such as modifying damage)… Here’s an example:

local gunmods = {
	BaseDamage = 100, 
	FireRate = 0.01, 
	ReloadTime = 0.1, 
	AmmoPerClip = math.huge, 
}
-- This changes a gun stats found in the Tool. 
local Gun = Character:FindFirstChild("Pistol")
local GunModule = require(Gun.Setting)
for modName, modValue in pairs(gunmods) do
           if rawget(GunModule, modName) then
                rawset(GunModule, modName, modValue)
            end
end

Is there any ways to patch this? Was thinking of cloning a clean modulescript everytime the tool is equipped but it seems very inefficient and slow.
Please note that this exploit is mostly used in FE GUN KIT (A popular free gun system module.)

Probably doesn’t do anything but I’ve seen people use table.freeze on their modules before.

1 Like

nah not really, even if you do patch it by setting an empty table __metatable and __index as your gunmod table people can still loop through the GC and find your table anyways, best bet is to handle the whole thing on the server

1 Like

Have the client only use the module for reference and everything else like the damage, ammo etc… handled on the server.

1 Like

I was thinking of that doing too, like replacing Humanoid:TakeDamage(BaseDamage) to just using Numbers for takedamage in server-script, but the problem is AmmoPerClip, i need it for the client for gui purposes.

How does table.freeze work exactly? do i just do table.freeze(GunSettings)? | GunSettings is the vanilla stats for the gun, not the modified one. (Which is gunmods) |

table.freeze basically freezes you’re table and it will not let you edit the table after that was run, the only argument is the table you want to freeze

local mySuperEpicTable = {
   ["key"] = "ldclx",
   ["damage"] = math.huge
}

mySuperEpicTable.damage = 1000 --> will work since it was run before the freeze
table.freeze(mySuperEpicTable)
mySuperEpicTable.damage = 1 --> wont work since it was run after the freeze