Creator Marketplace: Improving Model Safety

I second this.
Modern obfuscators significantly shuffle the AST of the output to prevent exactly this kind of analysis. If the marketplace models are going to be put under a static AST analysis then either the success rate will be very low or the amount of false positives will be very high.

3 Likes

This will help, but maybe the idea of permissions in properties or disabling Getfenv id in games would be more accurate, according to most replies.

2 Likes

It would be nice to know though what counts as obfuscated code.

4 Likes

If they tell us, It would help people get around it.

1 Like

Yeah, being vague only makes me nervous as to what does or does not count as obfuscated code. An example is necessary, crucial even.

These exactly! In an ideal marketplace we wouldn’t have to depend upon MainModules although Roblox’s attitude over the years has been to burn everything down instead of actually developing useful safer alternatives.

For us in the past, MainModules have been vital in deploying fixes for critical vulnerabilities and bugs. Without this functionality I doubt many developers would have manually updated their models, although I agree that we should absolutely advocate for better alternatives such as versioning.

It’s worth noting that a lot of younger users or less experiences developers are the ones utilising marketplace applications. If versioning tools were introduced they should be straight-forward to use, review and update.

Roblox did mention something along the lines of using packages (I believe?) to replace the behaviour of MainModules, although as fair as I’m aware they’re really limited right now and require the creator to individually grant permissions to users (which isn’t scalable at all).

17 Likes

I can assure you Mr. Bones will not get compromised, along with the rest of the Adonis Development Team, Nor will ForeverHD. Please understand the system you’re talking about before making drastic opinions on it. Adonis undergoes many updates a year including new features, and most imporantly, security fixes, which have prevented semi-major games from being backdoored multiple times in history. This should be a given. Nearly every maintained user-facing system has an automatic update system and the update server being compromised is never a realistic main concern.

Contributors, Developers, and Users are all acutely aware of what goes on inside the repo and when the nightly and mainmodule is updated. We are notified upon a new nightly and major release.

4 Likes

If the marketplace was a door that leaks when it rains, Roblox just replaces it with a wall instead of making the door more secure. They do this with most things.

8 Likes

This is why Roblox needs to learn that replacing the door with a wall is not better then replacing the door with a new door or heck even repairing it.

I can’t believe they have made these crazy changes the past few months

2 Likes

Anyways if someone needs a replacement for having a virtual Lua run thing which doesn’t use fenvs then here is one (I know this isn’t the #resources:community-resources page but i feel like its very important for me to share this)

Here is a virtual env implementation you can use for free

--!strict
--[[
	Description: A virtual enviroment implementation to replace the legacy function enviroments
	Author: github@ccuser44/ALE111_boiPNG
	Date: 15.2.2022
--]]

type dictionary = { [string]: any }
type func = (...any?) -> (...any?)

local globalEnv: dictionary = {
	-- // Libraries
	coroutine = coroutine,
	debug = debug,
	math = math,
	os = os,
	string = string,
	table = table,
	utf8 = utf8,
	bit32 = bit32,
	task = task,

	-- // Lua globals
	assert = assert,
	collectgarbage = function(action: string): number -- Use gcinfo instead
		assert(type(action) == "string", "invalid argument #1 to 'collectgarbage' (string expected, got "..type(action)..")")
		assert(action == "count", "collectgarbage must be called with 'count'; use gcinfo() instead")

		return gcinfo()
	end,
	error = error,
	getmetatable = getmetatable,
	ipairs = ipairs,
	newproxy = newproxy,
	next = next,
	pairs = pairs,
	pcall = pcall,
	print = print,
	rawequal = rawequal,
	rawget = rawget,
	rawset = rawset,
	select = select,
	setmetatable = setmetatable,
	tonumber = tonumber,
	tostring = tostring,
	type = type,
	unpack = unpack,
	xpcall = xpcall,
	warn = warn,
	gcinfo = gcinfo,
	_G = _G,
	_VERSION = _VERSION,

	-- // Roblox globals
	settings = settings,
	time = time,
	typeof = typeof,
	UserSettings = UserSettings,
	require = require,
	game = game,
	workspace = workspace,
	shared = shared,

	-- // Deprecated Roblox globals (Please don't use, use the alternative instead)
	delay = task.delay,-- Use task.delay instead
	spawn = task.defer,-- Use task.spawn instead
	wait = task.wait,-- Use task.wait instead
	elapsedTime = os.clock,-- Use os.clock instead
	stats = function(): Stats
		return game:GetService("Stats")
	end,-- Use game:GetService("Stats") instead
	tick = tick,-- Use os.time or os.clock instead

	-- // Roblox datatypes
	Axes = Axes,
	BrickColor = BrickColor,
	CatalogSearchParams = CatalogSearchParams,
	CFrame = CFrame,
	Color3 = Color3,
	ColorSequence = ColorSequence,
	ColorSequenceKeypoint = ColorSequenceKeypoint,
	DateTime = DateTime,
	DockWidgetPluginGuiInfo = DockWidgetPluginGuiInfo,
	Enum = Enum,
	Faces = Faces,
	FloatCurveKey = FloatCurveKey,
	Instance = Instance,
	NumberRange = NumberRange,
	NumberSequence = NumberSequence,
	NumberSequenceKeypoint = NumberSequenceKeypoint,
	OverlapParams = OverlapParams,
	PathWaypoint = PathWaypoint,
	PhysicalProperties = PhysicalProperties,
	Random = Random,
	Ray = Ray,
	RaycastParams = RaycastParams,
	Rect = Rect,
	Region3 = Region3,
	Region3int16 = Region3int16,
	TweenInfo = TweenInfo,
	UDim = UDim,
	UDim2 = UDim2,
	Vector2 = Vector2,
	Vector2int16 = Vector2int16,
	Vector3 = Vector3,
	Vector3int16 = Vector3int16,
}

table.freeze(globalEnv)

return function()
	local env: dictionary = {}

	for k, v in pairs(globalEnv) do
		env[k] = v
	end

	env._ENV = env :: dictionary

	env["getf".."env"] = function(target: (func | number)?): dictionary
		assert(type(target) == "number" or type(target) == "function" or type(target) == "nil", "invalid argument #1 to 'setf".."env' (number expected, got "..type(target)..")")
		assert(type(target) == "number" and target >= 0 or type(target) ~= "number", "invalid argument #1 to 'setf".."env' (level must be non-negative)")

		return env
	end

	env["setf".."env"] = function(target: func | number, newEnv: dictionary): ()
		assert(type(newEnv) == "table", "invalid argument #2 to 'setf".."env' (table expected, got "..type(newEnv)..")")
		assert(type(target) == "number" or type(target) == "function", "invalid argument #1 to 'setf".."env' (number expected, got "..type(target)..")")
		assert(type(target) == "number" and target >= 0, "invalid argument #1 to 'setf".."env' (level must be non-negative)")

		table.clear(env)

		for k: string, v: any in pairs(newEnv) do
			if type(k) == "string" then
				env[k] = v
			end
		end
	end

	-- // Stupid luau linter cant even recognise a metatable
	setmetatable(env, table.freeze({
		__index = globalEnv,
		__metatable = "The metatable is locked"
	}))

	return env
end

You can use this LBI made by Rerumu https://github.com/Rerumu/FiOne and input the virtual env to it.

Here is a full loadstring module which works with a VirtualEnv. \ /

https://roblox.com/library/9657684824/virtual-env-loadstring
Loadstring.rbxmx (192.4 KB)

You probably should also remove require, _G and shared from the VEnv script because Roblox might not like them. (Possibly)

7 Likes

Well, I think the community is partly to blame, We must drive Roblox crazy with our complaints and requested features/changes. But yeah they remove stuff instead of fixing it lol.

4 Likes

This is not the right direction at all. There are 4 major issues with these being blocked.

Fenv:

There are rare cases, mostly in plugins, where this is needed. If this change also applies to the plugin marketplace it diminishes an already small plugin creator community.

Require:

This function is vital to many scripts on roblox. First the post acts like auto update is not vital. In things like anti exploits and admin systems, auto updates are vital for the functionality because of the fact that they are exploit targets. Secondly the blocking of require makes it so no script on the marketplace can use modules. I hope I am mistaken in assuming that because blocking module scripts is detrimental to anything even slightly complex. Finally, many systems such as admin and vehicle systems use requires and they are essentially being forced to be diminished into one script.

Obfuscation:

Developer’s work is routinely stolen on the platform. Obfuscation allows the developer to keep their credit in what they make and at the same time allows them to control their use case. I will make a concession here in saying that those who say this is affecting strictly commercial products, such as blizzard, are wrong. This is because pay-to-use obfuscated systems are not meant to be on the public toolbox.

Monopolization:

Roblox, a platform that is built on the idea that anyone can build anything, is unintentionally supporting monopolies here. The idea of whitelisting models that use these methods just shows how important the methods are. By making a whitelist system, Roblox is essentially giving the top free models permanent prominence with no one else being able to make the same type of script without being on the special whitelist.

Conclusion

Model backdoors, malicious code, viruses, and the infamous “RoSync” have plagued games for years now; however, taking away user freedom is not the solution. Think back to when Roblox disabled HTTP requests by default. Scripts making malicious requests were blocked but the developer had the option to re-enable HTTP requests if they knew what they were doing and knew the risk. The option to allow or disable these methods is one that will be much better than blocking them all together. At the end of day, most malicious code infections are in small games by new developers (those who use the toolbox most). These relatively new developers would be protected by a system that disabled these methods by default because when they see a large warning they will hesitate to move forward. The harm done to legitimate actors is far greater than the benefit of community as a whole.

Thanks for reading,
MMCraftin :heart:

18 Likes

Many models in Roblox use require, getfenv, and setfenv for legitimate use-cases. These developers should not be punished due to the actions of bad actors unrelated to them.

Not only that, but Roblox has given absolutely no notice before this change. Have we not been over the debacle with the audio update and how little notice we’ve gotten with that? I can buy the fact that Roblox was under a serious time-constraint during all that, but I don’t see why Roblox could at least give us even just a week’s notice before this happened.

Absolutely unacceptable the way Roblox just dropped this on us.

11 Likes

I would like to add that not even regulars were notified about this. In some cases, they do get notice of updates, but for this, they got no notice.

Roblox seems to just be making a few decisions that have good intentions but are bad.

2 Likes

Why exactly was this pushed out with zero prior warning? Development on this platform is starting to get severely hindered lately and I, among other devs, are not happy. This immediately breaks things without giving a chance to remedy it making a lot of hard work rendered useless.

2 Likes

Fenvs can (mostly) be superseded by just coding things differently, like for example having modules import vargs on requiring.
If you need a code running enviroment like a loadstring module you can use my virtual env thing, Creator Marketplace: Improving Model Safety - #65 by ALE111_boiPNG

You can still have obfuscation by sharing a .rbxmx file which then loads the obfuscated code via HTTP service and runs it.

I totally agree with the require thing however, instead of Roblox allowing us to choose of disallowing 3rd party modules, they instead hide all public 3rd party requires. But the worst thing about this is that malicious models can actually bypass this restriction, meaning legitimate usecases are punished while leaving the malicious actors fine.
Also 3rd party modules are sadly the only way to make publicly updating things, unless you make some complicated system, this will definetly hurt legitimate Admin Command systems and other systems like Adonis.

2 Likes

Will people still be able to get scripts from the website? Is it just the studio built in marketplace effected?

1 Like

Roblox barely anybody wants this update so please listen to your community and not push this update.

There are better ways to go around this and either way back doors will always find a way, but blocking many useful scripts is not helpful to stopping back doors and viruses at all.

2 Likes

Also wanted to add. What about module scripts that must be public. I have a private modulescript that I had to make public because requires cannot call private scripts anymore. I’m not mass distributing this script through the tool box I’m just using it in groups that I work for. Will this script suddenly get banned?

And what about backwards compatibility? I’m the creator of a free tool called Encrypt API with hundreds of users. Will I suddenly get banned cause that tool I made 2 years ago has disallowed methods. What about the people that use the script? A core functionality of their game will just be broken now because I have to take my api off the marketplace.

1 Like

Not sure why this is here but being a regular on here gives you nothing but the ability to make bug reports (which members can already do). Wouldn’t push this stereotype here…

4 Likes