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.

criticalLuaudit check: asset-require

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, like require(script.Parent.Shop), is normal. A number, a variable holding a number or anything that builds one, like tonumber(...) 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

  • require on 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.