Loadstring() for one specific restricted use - any security risks?

If the player has no way to directly change the string that will be loaded into the Loadstring()

You should be fine. Do not put any text the player controls into loadstring, anything from a remote event should never be used, hackers can send any text they want through remote functions and events. Even their username could be a exploitive payload.

1 Like

If it is concatenated by my code running on a server side script, is it even possible for client side exploits to manipulate it?

Practically not, but it is not impossible;

You could just get unlucky where it accidentally creates an infinite loop. As unlikely as that may sound, you can never be too safe and should still use a blacklist filter to block certain keywords.

I am always very selective and cautious with what I send over remote events/functions, but I guess scripts with loadstring require a totally different league of cautiousness.

Any idea for keywords I should make a blacklist for? Of course any word that has something to do with the DatastoreService and MemoryStoreService will go in it, but is there anything else I should add?

I already gave you a few in my previous post. You can just scan through the Lua manual and add anything that sounds dangerous:
image

This will not be necessary if you override/delete the loadstring environment (also mentioned in my previous post) so that the function is incapable of accessing any Roblox-related stuff, even builtin functions like print.

1 Like

So only Lua words, nothing related to Roblox words as long as I set the proper loadstring environment.

basically yeah but there’s nothing stopping you from adding Roblox words to the filter too

You can also use the setfenv function to limit what the function that was returned has access to. I believe that this is what the game lua learning did also. I could be wrong though.

As for the setfenv(), I’ve never used it before. In the case formulaStr is the calculation string and env is the environment level, what should I set env as for the code below?

setfenv(assert(loadstring(formulaStr)),env)

env should be a dictionary where the variable name is the key, and the variable value is the value. For example, here’s how you “spy” on the print function:

local env = {
	print = function(...)
		warn(`there are {select('#', ...)} parameters passed to print`)
		print(...)
	end,
}

local code = [[
	print('hello', 'world')
]]

local f = loadstring(code)
setfenv(f, env)
print(f())

image

You would put a table with a list of all of the math functions or whatever other functions you want it to access. Something like this:

local allowed = {
    math.sin,
    math.cos,
   --...
}

you can see what it does if you try this:

local f = function()
	print("Hello World!")
end

setfenv(f, {})
f()

The setfenv makes it so that the function cannot access any global functions

Enabling loadstring does not pose any security risks unless you have a RemoteEvent that directly lets someone access the loadstring function on the server from the client. A way you can make sure that a string passed to loadstring doesn’t contain anything that could damage the server is by checking if the string contains any alphabetical characters.

local function IsSafe(String)
    String = string.gsub(String, "x", "*") -- Replace x with * since people tend to use it for multiplication

    return string.find(String, "%a") == nil   -- checks if the string has any letters, if it doesn't the function returns true and the string should be safe to use in loadstring()
end

print(IsSafe("(1 + 2) x 5")) -- true since it doesn't contain any letters besides x, which is whitelisted for multiplication.
print(IsSafe("workspace:ClearAllChildren()")) -- false since it contains letters

So for running the loadstring in a safe environment, I just need to call setfenv with the loadstring and an empty dictionary?

setfenv(f,{})
print(f())

That will only slow down your script, you should just check if the script contains any letters instead like I explained in my reply above

In the code I will load with loadstring() there are going to be functions from the math library, so instead I will make a copy of the string with all the math function words (I will make a list of allowed words) removed and then check for any remaining letters.
Shouldn’t be a problem if I do it like that to whitelist a few words, right?

Just sanitize the string and you’ll be just fine.

Thanks to all of you, I got my solution now. Thanks a lot.

This’ll work.

local function IsSafe(String)
    String = string.gsub(string.lower(String), "x", "")

    local Safe = true

    for Match in string.gmatch(String, "math%.(%w+)") do
        if not math[Match] then
            Safe = false
        end

        String = string.gsub(String, "math%." .. Match, "")
    end

    return Safe and string.find(String, "%a") == nil
end

print(IsSafe("math.sqrt(1 + 2) x 5"))
print(IsSafe("workspace:ClearAllChildren()"))

This doesn’t prevent making the server allocate huge amounts of memory by inputting huge tables. :troll: