String.rep doesn't respect script timeouts (Can invoke a consistent server "crash"/freeze)

string.rep, e.g. ("abc"):rep(123) does not track script timeouts and this can be abused to crash servers.

This started happening several years back, at least in 2018, though its probably existed pretty much forever.

This is especially tricky because strings have a metatable set to the string global meaning its contents can easily be accessed, but are impossible to properly sandbox without modification of user inputted code.

Repro:

  1. Create a new place
  2. Insert a script
  3. Put ("abcd"):rep(1e6) as its source (Note: For some reason, in some cases its necessary to place it in a call which utilizes the string, for example game:GetService(("abcd"):rep(1e6)), e.g. in studio, I believe its due to the output being expensive or potentially luau optimizations. That may suggest this bug isn’t directly related to string.rep)
  4. The game should freeze upon running, and the 15 second default timeout should not have an effect

This is causing problems in games which use script sandboxing for user code and no easy fix exists even with tools like my script sandbox titled H6x. It can be abused to consistently crash servers even in games where code execution is not utilized (as long as the repeat count is accessible)

This is potentially a really big problem for some games, with no proper solution.

Temporary workaround: In sandboxed code, replace rep globally with something else and properly sandbox code to avoid the rep function being accessed. If you use rep in your code don’t worry about it unless you give the user a way to customize the rep count in which case simply make sure its less than, for example, 1000.

3 Likes

string.rep used to be very expensive, but we’ve optimized it a month or so ago as a byproduct of general optimization of string library. It takes ~0.8 seconds on the server side to produce a 1 GB string (technically right now the limit is 2 GB but it’s going to go to 1 GB in the release next week for unrelated reasons). So generally speaking it should not be as expensive as to be able to singlehandedly bring a server down.

With Luau our eventual goal is to have the interpreter and the builtin library be completely timeout-safe (meaning, no amount of malicious code should be able to bypass the timeouts), although we are not there yet (there are some other constructs that can result in practically indefinite execution not caught by the timeout atm).

What you observe in Studio is different - it’s the Qt output widget struggling to print a few megabytes of text that GetService generates since that string is emphatically not a valid service name. I’ll let the team that works on the editor know although it’s unlikely to be very high priority to fix.

10 Likes

Thanks for this response, I’m glad you cleared this up.

It seems there is some way some people have found to cause servers to freeze by string.rep (but not directly by string.rep) and the way that I understood it was that string.rep was using up all kinds of CPU time, but, its clearly not that this is the case.

I did indeed go back and test this more thoroughly and its definitely not string.rep, what you’re saying with luau optimizations is accurate. I’ll have to look into it more and see if I can figure out exactly what’s happening.