Why require with an asset id is a backdoor risk
require(id) loads code from outside your game that its owner can change at any time. How to find these calls and what to replace them with.
What it looks like
Server code calls require with a number instead of a ModuleScript. That loads a module published on Roblox, which runs with full server access and can be changed by whoever owns it at any time.
Luau
require(1234567890)
How to detect it
- Search every server script and module for
require(and look at what's passed. A ModuleScript reference, likerequire(script.Parent.Shop), is normal. A number, a variable holding a number or anything that builds one, liketonumber(...)or arithmetic, is a finding. - Look for the id being hidden: split into pieces, stored in an attribute or a value object, read from a string, or passed through
getfenv. Those count as Hidden or scrambled code as well. - Check scripts inside models, tools and parts, not just
ServerScriptService. Free models are the usual source.
What an exploiter could do
Whoever owns the module can run any code they like in every server of the game, now or later. Common uses are giving themselves admin, adding hidden remotes, shutting servers down, or showing players unwanted content that puts the game at risk of moderation.
How to fix it
- Remove the
require. If the module is something the game really needs, get its source, read it, and add it to the game as your own ModuleScript. - If you can't tell what it does or why it's there, remove it and test. Legitimate games almost never need to load code by id.
- Check where the script came from. If it arrived inside a free model, remove the whole model and replace it with one you've checked.
Vulnerable example
Vulnerable
local Players = game:GetService("Players") local PlayerData = require(script.Parent.PlayerData) local leaderboardModule = 9876543210 local Leaderboard = require(leaderboardModule) :: any Players.PlayerAdded:Connect(function(player) Leaderboard.track(player, PlayerData.get) end)
Fixed example
Fixed
local Players = game:GetService("Players") local PlayerData = require(script.Parent.PlayerData) Players.PlayerAdded:Connect(function(player) local leaderstats = Instance.new("Folder") leaderstats.Name = "leaderstats" local coins = Instance.new("IntValue") coins.Name = "Coins" local profile = PlayerData.get(player) coins.Value = if profile then profile.Coins else 0 coins.Parent = leaderstats leaderstats.Parent = player end)
Common false positives
requireon a ModuleScript in the game, however it's found, isn't this check.- Code that only runs in Studio, guarded by
RunService:IsStudio(), such as loading a test helper, can't reach live servers. Mention it anyway, since it's an easy habit to carry into live code.