Coming Changes to Insert Service

We are making some changes to InsertService and wanted to give everyone some time to prepare and adjust their game if needed. We are making a change so that clients cannot by default use several InsertService functions. Specifically, this means that attempting to call LoadAsset or LoadAssetVersion from a LocalScript will create a error and will not load the specified model. Allowing the client to insert arbitrary assets is a huge security risk that is really not worth the convenience. We are planning on enabling this change on November 17.

You can opt-out of this feature by setting InsertService.AllowClientInsertModels to true, but it is highly recommended that you only enable this to buy yourself some time while you migrate your code to the server. If you leave this setting on true, you are exposing your game to unnecessary risk. This setting can only be changed in Studio (although you can always read the value in a script).

If you are using InsertService in a LocalScript, you can change your code so that instead of calling LoadAsset on the client, you can have the client fire a RemoteEvent so that the server can load in the model. One very important point though, you should never just pass in the ID of the asset you want to load. Exploiters can call RemoteEvents with whatever arguments they like, so passing the id nullifies any security you get from running LoadAsset on the server.

#Example

In most cases you can simply use a RemoteEvent when you want to load a model from a player’s input. In the following example we have a game with a pizza button. When the button is pressed, the player gets a slice of pizza added to their backpack. Here is how the code would look with client-side insertion:

local button = script.Parent
local player = game.Players.LocalPlayer
local InsertService = game:GetService("InsertService")
local pizzaId = 175696937

local function onButtonClicked()
	local pizzaModel
	local success, message = pcall(function()
		pizzaModel = InsertService:LoadAsset(pizzaId)
	end)
	if success then
		local pizzaTool = pizzaModel:GetChildren()[1]
		pizzaTool.Parent = player.Backpack
	else
		warn("Error loading pizza model: " .. message)
	end
end

button.MouseButton1Click:Connect(onButtonClicked)

To make this work on the server, we will need a LocalScript to listen for the button input, a RemoteEvent for the LocalScript to fire, and a Script on the server listening to the remote that will be responsible for fetching the asset and giving it to the player. Here is what the LocalScript will look like:

local button = script.Parent
local requestEvent = game.ReplicatedStorage.RequestItem

local function onButtonClicked()
	requestEvent:FireServer("Pizza")
end

button.MouseButton1Click:Connect(onButtonClicked)

Super simple - just fire the RemoteEvent when the player clicks on the button. In general, the client should just deal with the interface, and should send messages to the server when the player wants to do something. Now let’s look at the Script on the server:

local requestEvent = game.ReplicatedStorage.RequestItem
local InsertService = game:GetService("InsertService")

local items = {
	Pizza = 175696937,	
	Sword = 47433,
	Slingshot = 47620
}

local function onRequestEvent(player, itemName)
	local itemId = items[itemName]
	local model
	local success, message = pcall(function()
		model = InsertService:LoadAsset(itemId)
	end)
	if model then
		local tool = model:GetChildren()[1]
		tool.Parent = player.Backpack
	else
		warn("Error loading " .. itemName .. " : " .. message)
	end
end

requestEvent.OnServerEvent:Connect(onRequestEvent)

The server makes a table of all of the assets the game wants the player to be allowed access to. Again, this is so that the client isn’t passing an id to the server. Instead, it passes a string. The server then uses this string to look up the id in a table. After that, things are fairly straightforward. The server gets the model through LoadAsset and then puts the contents into the calling player’s backpack.

#More Resources

For more on RemoteEvents and RemoteFunctions, see

You should also check out FilteringEnabled as it is another great security feature

33 Likes

Oo. I like this. I’ve seen one too many exploits that use the place owner’s models.

5 Likes

Some games only replicate models or map chunks on a need-to-know basis (this makes load times extremely fast), and don’t have a good way to replicate instances to a client without it replicating to all clients. I know some people use client-side InsertService to solve this. My game does a lot of cloning and destroying in the player’s PlayerGui on both the server and client to achieve this without the server running out of memory.

http://devforum.roblox.com/t/replicating-orphaned-instances-via-remoteevents-remotefunctions/15007

2 Likes

Client-side inserts cause the model to be replicated to all other clients, so there shouldn’t be any adverse effects to calling LoadAsset on the server instead of the client.

Even with FilteringEnabled? :open_mouth:

1 Like

Yes.

1 Like

Will this fix apply to inserting models using this method:

game:GetObjects("rbxassetid://assetid")[1].Parent = parent	

I know a few exploits that have been used in my game have been distributed by running something like this on the client, where the asset is a module made and maintained by the exploit developer:

loadstring(game:GetObjects("rbxassetid://assetid")[1].Source)()	

Both loadstring and GetObjects have been removed from the game client. These are features added by the exploit.

7 Likes

What about modules? If I require a module with ROBLOX objects parented to it, will those replicate when the module is required by AssetId since modules required in this manner are parented to nil? Or do they go through InsertService first?

1 Like

Modules required by asset ID are not parented to the DataModel so they will not replicate unless you move them into the DataModel.

2 Likes

Don’t they get added as a model to a folder in InsertService?
(seems like InsertService now has a few folders for organizing using a totally unknown pattern)

The following places may need to be updated:

137877687   Firebrand1        RoCitizens
530323958   Obby Productions  Escape The Evil Clown Obby (NEW!)
506546686   orinrino619       [LUCKY BLOCKS!] Random Gear Wars!! [Minecraft] α
416770565   Obby Productions  Escape The Waterpark Obby (NEW!)
425947849   Zedreadr          Vanish Cap under the Moat
266630637   hunt220           Teen Titans GO! [RP!]
422776634   Zedreadr          Jolly Roger Bay
478396631   xXFIREFACEXx      [LUCKY BLOCKS!] Hat Warfare Tycoon
192800      Dued1             Work at a Pizza Place
92898409    Donald_Trump      The Neighborhood of Robloxia [V.5]
436611033   firebreathingdragon6 (Justice League!) Super Hero Tycoon!
414288170   The Money Team™   Donut Factory Tycoon! | NEW!
26838733    Sky Studios       Catalog Heaven
444664549   PlatinumFalls     Escape the Evil Farm! (READ DESC)
339293087   Tremity           Adopt and Raise a Cute Kid
433413112   jonasgarcia       Blow up The characters
216972437   Npinoy            [Read Desc!]! RO-BLOX Tycoon!
114890690   Games_Page        (Sparkes fixed) Life in Paradise
147289696   Zedreadr          Super Mario 64 ROBLOX Edition!(Gamepasses!)
221960141   joshman601        2012 Disaster Movie Survival (Earthquake's, meteor
195845601   PlatinumFalls     Escape the Gym! (READ DESC)
399595838   teamkilled        Design It!
120077860   MagicSteak        DO NOT PLAY
453312834   Numoji            Rollernauts
413915687   Mr_Supernoob      undertale: sans vs chara (spoilers)

This is based on reporting from the gameserver. If you have a non-fe place and don’t even use insert service, your place might be listed due to exploits.

5 Likes