roblox-security
Skill92 starsChanged 47 days agoMITView on GitHub
Anti-exploit design - never trust the client, validate every remote argument (NaN, spoofed instances, strings), rate limiting, ProximityPrompt/ClickDetector abuse, network ownership, movement and hit validation, economy/trade duplication, code confidentiality, secure teleports, Device Trust API, heuristics, Ban API. Use when writing server handlers for client input, combat/economy/trading, or reviewing for exploits.
4 other projects use a version of this.
Adopted by
Most recently taken up by
- rodrigo-guerraa/roblox-hubtheir own version, first seen Oct 17, 2026
- TabooHarmony/roblox-braintheir own version, first seen Sep 23, 2026
- szlay/roblox-basetheir own version, first seen Jul 24, 2026
- sentinelcore/roblox-skillstheir own version, first seen Feb 23, 2026
Other versions4 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 4
- TabooHarmony/roblox-brain★ 150same name
- sentinelcore/roblox-skills★ 18same name
- rodrigo-guerraa/roblox-hub★ 2same name
- szlay/roblox-base★ 1same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository25 other files it gives its agents.
- AGENTS.mdAGENTS.md
- docs/agents.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- roblox-analytics-liveopsSkill
- roblox-architectureSkill
- roblox-audioSkill
- roblox-characters-animationSkill
- roblox-code-reviewSkill
- roblox-data-storesSkill
- roblox-game-systemsSkill
- roblox-inputSkill
- roblox-luauSkill
- roblox-monetizationSkill
- roblox-networkingSkill
- roblox-npc-aiSkill
- roblox-open-cloudSkill
- roblox-performanceSkill
- roblox-physicsSkill
- roblox-studio-mcpSkill
- roblox-teleport-matchmakingSkill
- roblox-testingSkill
- roblox-text-chatSkill
- roblox-toolingSkill
- roblox-uiSkill
- roblox-world-buildingSkill
The file
We split this skill into the rules it gives an agent
7 rules. 0 are common, 0 are distinctive, and 7 are very specific to this project.
0
Common
Most of the 3 edited versions we read keep these.
0
Distinctive
This author's own choices. Worth a look.
7
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 82
Treat every handler parameter after player as unknown and narrow it with these helpers.
- Very specific: line 83
Look items up by ID in server tables (ITEMS[itemId]).
- Very specific: line 137
If these objects sit in unanchored parts the client can own, an exploiter can pull the part to themselves: anchor them, or …
- Very specific: line 151
Keep gameplay-critical unanchored parts server-owned: part:SetNetworkOwner(nil).
- Very specific: line 178
Never put API keys in scripts or attributes.
- Very specific: line 187
Prefer routing (ranked place for Standard/Full) or gating features (trading) over rejecting players.
- Very specific: line 189
Treat Pending as untrusted for sensitive features.
“Common” is measured: kept by at least 6 in 10 of the 3 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Roblox security
Exploiters fully control their client: they can run any Luau, read every replicated script
(decompiled), fire any remote with any arguments at any rate, edit any local property (WalkSpeed,
prompt Enabled, MaxActivationDistance), and move anything they have network ownership of.
Client-side anti-cheat is at best a speed bump. Security comes from server design.
Core rules
- The server decides. Clients send intent ("I pressed attack aiming here"), never results ("I dealt 50 damage", "give me 100 coins").
- Validate every argument of every
OnServerEvent/OnServerInvoke: type, structure, range, finiteness. - Validate context: is the player alive, in range, not on cooldown, owns the item, allowed to act?
- Rate limit everything a client can trigger (remotes, prompts, touches, clicks).
- Keep secrets server-side: server code in
ServerScriptService/ServerStorage; API keys viaHttpService:GetSecret(); never ship unreleased content to production places. - Prefer silent mitigation (drop, clamp, correct state) over instant kicks; escalate on repeated signals.
Argument validation toolkit
--!strict
-- ServerScriptService/Server/Validate.luau
local Validate = {}
function Validate.number(value: unknown, min: number, max: number): number?
if typeof(value) ~= "number" or not math.isfinite(value) then
return nil -- rejects NaN and ±inf (NaN fails every comparison, so range checks alone don't catch it)
end
if value < min or value > max then
return nil
end
return value
end
function Validate.integer(value: unknown, min: number, max: number): number?
local n = Validate.number(value, min, max)
return if n and n == math.floor(n) then n else nil
end
function Validate.string(value: unknown, maxLength: number): string?
if typeof(value) ~= "string" or #value > maxLength or utf8.len(value) == nil then
return nil -- also rejects invalid UTF-8 (which DataStores refuse)
end
return value
end
function Validate.vector3(value: unknown, maxMagnitude: number): Vector3?
if typeof(value) ~= "Vector3" then
return nil
end
if not (math.isfinite(value.X) and math.isfinite(value.Y) and math.isfinite(value.Z)) then
return nil
end
return if value.Magnitude <= maxMagnitude then value else nil
end
-- Accept only a real instance of the expected class that lives under a trusted container.
-- Exploiters can send tables shaped like instances ({ ClassName = "Part", ... }).
function Validate.instanceIn(value: unknown, className: string, container: Instance): Instance?
if typeof(value) ~= "Instance" or not value:IsA(className) or not value:IsDescendantOf(container) then
return nil
end
return value
end
function Validate.enum<T>(value: unknown, allowed: { [T]: boolean }): T?
if allowed[value :: any] then
return value :: any
end
return nil
end
return Validate- Treat every handler parameter after
playerasunknownand narrow it with these helpers. - Look items up by ID in server tables (
ITEMS[itemId]); never read prices/stats from client data or from replicatedNumberValues the client could reference. - Cap table sizes and iterate client tables defensively (keys may be NaN-like, nested, huge).
Rate limiting (token bucket)
--!strict
local Players = game:GetService("Players")
type Bucket = { tokens: number, last: number }
local function newLimiter(capacity: number, windowSeconds: number)
local refillRate = capacity / windowSeconds
local buckets: { [Player]: Bucket } = {}
Players.PlayerRemoving:Connect(function(player)
buckets[player] = nil
end)
return function(player: Player): boolean
local now = os.clock()
local bucket = buckets[player]
if not bucket then
bucket = { tokens = capacity, last = now }
buckets[player] = bucket
else
bucket.tokens = math.min(capacity, bucket.tokens + (now - bucket.last) * refillRate)
bucket.last = now
end
if bucket.tokens >= 1 then
bucket.tokens -= 1
return true
end
return false
end
end
local allowAttack = newLimiter(5, 1) -- bursts of 5, refills 5/second
print(allowAttack)Rate-limit expensive or exploitable operations especially: DataStore/Badge/HTTP calls (they have their own budgets), cloning large models, teleports, currency grants, anything broadcast to all clients.
Client-triggered instances are not safe
| Object | What exploiters can do | Server must |
ProximityPrompt | Fire events while disabled; change distance/line-of-sight/HoldDuration locally. Only Triggered gets a distance check. | Re-check enabled state, distance from character, alive, cooldown. |
ClickDetector | Fire from any distance even when disabled. No server checks at all. | Same as above. |
DragDetector | Inherited click events unchecked; drag respects only Enabled and PermissionPolicy. | Validate drag results on the server. |
Touched on client-owned parts | Fake or suppress touches. | Validate with server-side distance/overlap queries. |
If these objects sit in unanchored parts the client can own, an exploiter can pull the part to
themselves: anchor them, or part:SetNetworkOwner(nil) for server ownership.
Network ownership and movement
Clients own their character's physics, so they can teleport, fly, noclip, speed hack, fling other
players (NaN/huge velocities), and suppress Touched. Options, strongest first:
- Server authority (Workspace
AuthorityMode = Server; fully released, opt-in): the server simulates movement with client prediction and rollback, eliminating movement exploits. Seeroblox-physics. - Server-side movement checks: compare horizontal (XZ) displacement per interval against max speed plus latency tolerance; exempt legitimate teleports (set a flag server-side when you move them); rubber-band to the last valid position instead of kicking.
- Keep gameplay-critical unanchored parts server-owned:
part:SetNetworkOwner(nil).
Combat validation (hit reports)
Client sends origin, direction/target part, and timestamp. Server checks:
- Origin is near the character's server position (tolerance scaled by
player:GetNetworkPing()). - Target is alive, an enemy, and within weapon range; claimed hit point is near the target's server position.
- A server raycast against static geometry finds no wall between origin and target.
- Fire rate, ammo, reload/sprint state tracked on the server.
Economy, trading, purchases
- Currency, inventory, and prices exist only on the server. Clients request; the server checks balance and applies changes atomically.
- Trades: validate both sides fully, then commit both, then save both; on any failure revert everything. Beware "trade then leave before save" duplication: lock items during trades and save immediately after.
- Robux purchases: grant only in
MarketplaceService.ProcessReceipt(developer products) or after a server ownership check (passes). Never trustPromptProductPurchaseFinishedfrom the client. Seeroblox-monetization.
Confidentiality
- Any
LocalScript, clientScript, orModuleScriptthat replicates can be decompiled — even if disabled or never required. Don't mix server-only branches into shared modules. - Anything replicated (models, UI, attributes) can be data-mined. Keep unreleased content in separate private universes, not hidden in production.
- Clients can teleport to any place in the universe: set Access Control for Places → Secure within universe only in Creator Dashboard, and verify eligibility on join in restricted places (default deny).
- Never put API keys in scripts or attributes; use the in-experience Secrets store (
HttpService:GetSecret).
Device trust (hardware attestation)
Player.DeviceTrustLevel (server-read) reports Pending → Unknown / None / Standard / Full. Supported
today on Android, Chromebook, and Meta Quest; web reports None; iOS, desktop, and consoles report Unknown
until supported (Unknown ≠ untrusted). Studio is always Pending. It describes the device, not the
player — it complements server validation, never replaces it.
- Prefer routing (ranked place for
Standard/Full) or gating features (trading) over rejecting players; check the impact first in Creator Hub → Safety → Anti-cheat. - Treat
Pendingas untrusted for sensitive features. Decide on the server; tell the client via a remote. - To reject on join, assign the one-per-place callback in a server script:
--!strict
local IntegrityService = game:GetService("IntegrityService")
type Decision = { Action: Enum.PlayerDeviceTrustDecision, Message: string? }
IntegrityService.EvaluatePlayerDeviceTrust = function(player: Player, _measures): Decision
if player.DeviceTrustLevel == Enum.PlayerDeviceTrustLevel.None then
return { Action = Enum.PlayerDeviceTrustDecision.Reject, Message = "This game can't verify your device." }
end
return { Action = Enum.PlayerDeviceTrustDecision.Accept }
endDetection and consequences
Layer server-side heuristics on top of validation: fastest-possible completion time, rate of resource gain, inhumanly regular action cadence, honeypot remotes no legit client fires. Accumulate a suspicion score; act on multiple signals. Ladder: silent logging → quiet mitigation → restrict features → kick/ban. Delay visible consequences so exploiters can't bisect your checks.
--!strict
local Players = game:GetService("Players")
local function banForExploiting(player: Player, evidence: string)
local ok, err = pcall(function()
Players:BanAsync({
UserIds = { player.UserId },
Duration = 7 * 24 * 60 * 60, -- seconds; -1 = permanent
DisplayReason = "Exploiting detected.", -- shown to the user (max 400 chars, filtered)
PrivateReason = evidence, -- visible to you only
ExcludeAltAccounts = false, -- also ban detected alt accounts
ApplyToUniverse = true,
})
end)
if not ok then
warn("BanAsync failed:", err)
player:Kick("Exploiting detected.")
end
end
return banForExploitingEnable Players.BanningEnabled for the Ban API. Prefer reversible, time-limited bans (check
Players:GetBanHistoryAsync to escalate); version detection rules and monitor false-positive rates.
Security review checklist and common vulnerable-code patterns: references/checklist.md.
Related skills
roblox-networking, roblox-physics (ownership, server authority), roblox-data-stores,
roblox-monetization, roblox-code-review.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

