Загрузка данных
--[[
CLIENT EXPOSURE AUDITOR v5
Menu-first build.
Behavior:
1) On execution, ONLY a small "AUDIT" launcher appears.
2) Clicking it opens the debugger menu.
3) No scan runs until you press a scan button.
4) Results are grouped by scan type and paginated.
5) Close (X) hides the window; launcher remains available.
Scope:
- Uses normal Roblox client APIs only.
- Does NOT use executor-specific introspection such as getgc,
getsenv, debug registry, hooks, decompilers, or remote firing.
- Read-only audit: it does not invoke remotes/prompts or mutate game state.
]]
local Players = game:GetService("Players")
local CollectionService = game:GetService("CollectionService")
local UserInputService = game:GetService("UserInputService")
local RunService = game:GetService("RunService")
local player = Players.LocalPlayer
if not player then
warn("[AUDIT] LocalPlayer unavailable.")
return
end
local playerGui = player:WaitForChild("PlayerGui")
----------------------------------------------------------------
-- CLEAN PREVIOUS INSTANCE
----------------------------------------------------------------
local GUI_NAME = "client_exposure_auditor_v5"
local old = playerGui:FindFirstChild(GUI_NAME)
if old then
old:Destroy()
end
----------------------------------------------------------------
-- COLORS / CONSTANTS
----------------------------------------------------------------
local C = {
bg = Color3.fromRGB(14, 15, 18),
panel = Color3.fromRGB(21, 23, 28),
panel2 = Color3.fromRGB(28, 30, 36),
panel3 = Color3.fromRGB(35, 38, 45),
text = Color3.fromRGB(236, 238, 242),
muted = Color3.fromRGB(157, 163, 175),
accent = Color3.fromRGB(77, 133, 255),
accent2 = Color3.fromRGB(99, 154, 255),
ok = Color3.fromRGB(83, 196, 126),
warn = Color3.fromRGB(242, 187, 74),
danger = Color3.fromRGB(239, 97, 97),
border = Color3.fromRGB(58, 62, 73),
}
local PAGE_SIZE = 80
local MAX_RESULTS_PER_SCAN = 20000
----------------------------------------------------------------
-- UTIL
----------------------------------------------------------------
local function corner(parent, radius)
local x = Instance.new("UICorner")
x.CornerRadius = UDim.new(0, radius or 8)
x.Parent = parent
return x
end
local function stroke(parent, color, thickness, transparency)
local x = Instance.new("UIStroke")
x.Color = color or C.border
x.Thickness = thickness or 1
x.Transparency = transparency or 0
x.Parent = parent
return x
end
local function safeFullName(obj)
local ok, value = pcall(function()
return obj:GetFullName()
end)
return ok and value or obj.Name
end
local function safeRead(obj, property)
local ok, value = pcall(function()
return obj[property]
end)
if ok then
return value
end
return nil
end
local function valueToString(value)
local t = typeof(value)
if t == "Instance" then
return safeFullName(value)
elseif t == "string" then
if #value > 240 then
return value:sub(1, 240) .. "..."
end
return value
elseif t == "Vector3" or t == "Vector2" or t == "CFrame"
or t == "Color3" or t == "UDim" or t == "UDim2"
or t == "NumberRange" or t == "NumberSequence"
or t == "ColorSequence" or t == "BrickColor"
or t == "EnumItem" then
return tostring(value)
elseif t == "table" then
return "<table>"
end
return tostring(value)
end
local sensitiveWords = {
"secret", "token", "password", "apikey", "api_key", "private",
"admin", "owner", "moderator", "money", "cash", "coin", "currency",
"reward", "price", "damage", "cooldown", "inventory", "item",
"weapon", "level", "xp", "experience", "config", "settings",
"ban", "anticheat", "anti_cheat", "remote", "purchase", "give", "grant",
}
local function riskLevel(text)
local s = string.lower(text)
for _, word in ipairs({"password", "secret", "token", "apikey", "api_key"}) do
if string.find(s, word, 1, true) then
return "HIGH"
end
end
for _, word in ipairs(sensitiveWords) do
if string.find(s, word, 1, true) then
return "MEDIUM"
end
end
return "INFO"
end
----------------------------------------------------------------
-- GUI ROOT
----------------------------------------------------------------
local gui = Instance.new("ScreenGui")
gui.Name = GUI_NAME
gui.ResetOnSpawn = false
gui.IgnoreGuiInset = true
gui.DisplayOrder = 999999
gui.ZIndexBehavior = Enum.ZIndexBehavior.Sibling
gui.Parent = playerGui
----------------------------------------------------------------
-- LAUNCH BUTTON
----------------------------------------------------------------
local launcher = Instance.new("TextButton")
launcher.Name = "launcher"
launcher.Size = UDim2.fromOffset(92, 40)
launcher.Position = UDim2.new(0, 18, 0.5, -20)
launcher.BackgroundColor3 = C.accent
launcher.BorderSizePixel = 0
launcher.AutoButtonColor = true
launcher.Text = "AUDIT"
launcher.TextColor3 = Color3.new(1, 1, 1)
launcher.TextSize = 15
launcher.Font = Enum.Font.GothamBold
launcher.ZIndex = 100
launcher.Parent = gui
corner(launcher, 10)
stroke(launcher, Color3.fromRGB(125, 166, 255), 1, 0.35)
----------------------------------------------------------------
-- MAIN WINDOW
----------------------------------------------------------------
local main = Instance.new("Frame")
main.Name = "main"
main.Size = UDim2.new(0.88, 0, 0.82, 0)
main.Position = UDim2.new(0.06, 0, 0.09, 0)
main.BackgroundColor3 = C.bg
main.BorderSizePixel = 0
main.Visible = false
main.ZIndex = 20
main.Parent = gui
corner(main, 12)
stroke(main, C.border, 1, 0.2)
local sizeConstraint = Instance.new("UISizeConstraint")
sizeConstraint.MinSize = Vector2.new(760, 480)
sizeConstraint.MaxSize = Vector2.new(1450, 900)
sizeConstraint.Parent = main
----------------------------------------------------------------
-- TOP BAR
----------------------------------------------------------------
local top = Instance.new("Frame")
top.Name = "top"
top.Size = UDim2.new(1, 0, 0, 54)
top.BackgroundColor3 = C.panel
top.BorderSizePixel = 0
top.ZIndex = 21
top.Parent = main
local title = Instance.new("TextLabel")
title.Size = UDim2.new(1, -180, 1, 0)
title.Position = UDim2.fromOffset(18, 0)
title.BackgroundTransparency = 1
title.Text = "CLIENT EXPOSURE AUDITOR"
title.TextColor3 = C.text
title.Font = Enum.Font.GothamBold
title.TextSize = 18
title.TextXAlignment = Enum.TextXAlignment.Left
title.ZIndex = 22
title.Parent = top
local subtitle = Instance.new("TextLabel")
subtitle.Size = UDim2.new(0, 380, 0, 18)
subtitle.Position = UDim2.new(0, 18, 1, -18)
subtitle.BackgroundTransparency = 1
subtitle.Text = "No automatic scan • choose a module on the left"
subtitle.TextColor3 = C.muted
subtitle.Font = Enum.Font.Gotham
subtitle.TextSize = 11
subtitle.TextXAlignment = Enum.TextXAlignment.Left
subtitle.ZIndex = 22
subtitle.Parent = top
local minimize = Instance.new("TextButton")
minimize.Size = UDim2.fromOffset(38, 34)
minimize.Position = UDim2.new(1, -86, 0, 10)
minimize.BackgroundColor3 = C.panel3
minimize.BorderSizePixel = 0
minimize.Text = "—"
minimize.TextColor3 = C.text
minimize.TextSize = 20
minimize.Font = Enum.Font.GothamBold
minimize.ZIndex = 30
minimize.Parent = top
corner(minimize, 8)
local close = Instance.new("TextButton")
close.Name = "close"
close.Size = UDim2.fromOffset(38, 34)
close.Position = UDim2.new(1, -44, 0, 10)
close.BackgroundColor3 = Color3.fromRGB(65, 36, 41)
close.BorderSizePixel = 0
close.Text = "×"
close.TextColor3 = Color3.fromRGB(255, 208, 208)
close.TextSize = 22
close.Font = Enum.Font.GothamBold
close.ZIndex = 30
close.Parent = top
corner(close, 8)
----------------------------------------------------------------
-- LEFT SIDEBAR
----------------------------------------------------------------
local sidebar = Instance.new("Frame")
sidebar.Size = UDim2.new(0, 210, 1, -54)
sidebar.Position = UDim2.fromOffset(0, 54)
sidebar.BackgroundColor3 = C.panel
sidebar.BorderSizePixel = 0
sidebar.ZIndex = 21
sidebar.Parent = main
local sidebarPadding = Instance.new("UIPadding")
sidebarPadding.PaddingTop = UDim.new(0, 12)
sidebarPadding.PaddingLeft = UDim.new(0, 10)
sidebarPadding.PaddingRight = UDim.new(0, 10)
sidebarPadding.Parent = sidebar
local sidebarList = Instance.new("UIListLayout")
sidebarList.Padding = UDim.new(0, 7)
sidebarList.SortOrder = Enum.SortOrder.LayoutOrder
sidebarList.Parent = sidebar
local function makeNav(text, order)
local b = Instance.new("TextButton")
b.Size = UDim2.new(1, 0, 0, 38)
b.BackgroundColor3 = C.panel2
b.BorderSizePixel = 0
b.Text = text
b.TextColor3 = C.text
b.TextSize = 13
b.Font = Enum.Font.GothamMedium
b.TextXAlignment = Enum.TextXAlignment.Left
b.AutoButtonColor = true
b.LayoutOrder = order
b.ZIndex = 22
b.Parent = sidebar
corner(b, 8)
local p = Instance.new("UIPadding")
p.PaddingLeft = UDim.new(0, 12)
p.Parent = b
return b
end
local btnOverview = makeNav("Overview", 1)
local btnRemotes = makeNav("Scan Remotes", 2)
local btnCode = makeNav("Scan Client Code", 3)
local btnState = makeNav("Scan State / Values", 4)
local btnInteractions = makeNav("Scan Interactions", 5)
local btnPhysics = makeNav("Scan Physics", 6)
local btnAssets = makeNav("Scan Assets", 7)
local btnRisks = makeNav("Show Risks", 8)
local separator = Instance.new("Frame")
separator.Size = UDim2.new(1, 0, 0, 1)
separator.BackgroundColor3 = C.border
separator.BorderSizePixel = 0
separator.LayoutOrder = 9
separator.ZIndex = 22
separator.Parent = sidebar
local btnFull = makeNav("FULL SCAN", 10)
btnFull.BackgroundColor3 = Color3.fromRGB(44, 74, 132)
local btnClear = makeNav("Clear Results", 11)
----------------------------------------------------------------
-- CONTENT
----------------------------------------------------------------
local content = Instance.new("Frame")
content.Size = UDim2.new(1, -210, 1, -54)
content.Position = UDim2.fromOffset(210, 54)
content.BackgroundColor3 = C.bg
content.BorderSizePixel = 0
content.ZIndex = 21
content.Parent = main
local statusBar = Instance.new("Frame")
statusBar.Size = UDim2.new(1, -24, 0, 44)
statusBar.Position = UDim2.fromOffset(12, 12)
statusBar.BackgroundColor3 = C.panel
statusBar.BorderSizePixel = 0
statusBar.ZIndex = 22
statusBar.Parent = content
corner(statusBar, 9)
local status = Instance.new("TextLabel")
status.Size = UDim2.new(1, -170, 1, 0)
status.Position = UDim2.fromOffset(14, 0)
status.BackgroundTransparency = 1
status.Text = "READY — choose a scan"
status.TextColor3 = C.ok
status.Font = Enum.Font.GothamBold
status.TextSize = 12
status.TextXAlignment = Enum.TextXAlignment.Left
status.ZIndex = 23
status.Parent = statusBar
local countLabel = Instance.new("TextLabel")
countLabel.Size = UDim2.fromOffset(150, 44)
countLabel.Position = UDim2.new(1, -158, 0, 0)
countLabel.BackgroundTransparency = 1
countLabel.Text = "0 results"
countLabel.TextColor3 = C.muted
countLabel.Font = Enum.Font.Gotham
countLabel.TextSize = 12
countLabel.TextXAlignment = Enum.TextXAlignment.Right
countLabel.ZIndex = 23
countLabel.Parent = statusBar
local sectionTitle = Instance.new("TextLabel")
sectionTitle.Size = UDim2.new(1, -24, 0, 30)
sectionTitle.Position = UDim2.fromOffset(12, 66)
sectionTitle.BackgroundTransparency = 1
sectionTitle.Text = "Overview"
sectionTitle.TextColor3 = C.text
sectionTitle.Font = Enum.Font.GothamBold
sectionTitle.TextSize = 17
sectionTitle.TextXAlignment = Enum.TextXAlignment.Left
sectionTitle.ZIndex = 22
sectionTitle.Parent = content
local resultsFrame = Instance.new("Frame")
resultsFrame.Size = UDim2.new(1, -24, 1, -146)
resultsFrame.Position = UDim2.fromOffset(12, 98)
resultsFrame.BackgroundColor3 = C.panel
resultsFrame.BorderSizePixel = 0
resultsFrame.ClipsDescendants = true
resultsFrame.ZIndex = 22
resultsFrame.Parent = content
corner(resultsFrame, 9)
local scrolling = Instance.new("ScrollingFrame")
scrolling.Size = UDim2.new(1, -10, 1, -50)
scrolling.Position = UDim2.fromOffset(5, 5)
scrolling.BackgroundTransparency = 1
scrolling.BorderSizePixel = 0
scrolling.ScrollBarThickness = 6
scrolling.ScrollBarImageColor3 = C.border
scrolling.CanvasSize = UDim2.fromOffset(0, 0)
scrolling.AutomaticCanvasSize = Enum.AutomaticSize.Y
scrolling.ZIndex = 23
scrolling.Parent = resultsFrame
local resultList = Instance.new("UIListLayout")
resultList.Padding = UDim.new(0, 4)
resultList.SortOrder = Enum.SortOrder.LayoutOrder
resultList.Parent = scrolling
local resultPadding = Instance.new("UIPadding")
resultPadding.PaddingLeft = UDim.new(0, 5)
resultPadding.PaddingRight = UDim.new(0, 5)
resultPadding.PaddingTop = UDim.new(0, 3)
resultPadding.PaddingBottom = UDim.new(0, 3)
resultPadding.Parent = scrolling
local footer = Instance.new("Frame")
footer.Size = UDim2.new(1, 0, 0, 40)
footer.Position = UDim2.new(0, 0, 1, -40)
footer.BackgroundColor3 = C.panel2
footer.BorderSizePixel = 0
footer.ZIndex = 24
footer.Parent = resultsFrame
local prevPage = Instance.new("TextButton")
prevPage.Size = UDim2.fromOffset(72, 28)
prevPage.Position = UDim2.fromOffset(8, 6)
prevPage.BackgroundColor3 = C.panel3
prevPage.BorderSizePixel = 0
prevPage.Text = "< Prev"
prevPage.TextColor3 = C.text
prevPage.TextSize = 12
prevPage.Font = Enum.Font.GothamMedium
prevPage.ZIndex = 25
prevPage.Parent = footer
corner(prevPage, 7)
local nextPage = Instance.new("TextButton")
nextPage.Size = UDim2.fromOffset(72, 28)
nextPage.Position = UDim2.new(1, -80, 0, 6)
nextPage.BackgroundColor3 = C.panel3
nextPage.BorderSizePixel = 0
nextPage.Text = "Next >"
nextPage.TextColor3 = C.text
nextPage.TextSize = 12
nextPage.Font = Enum.Font.GothamMedium
nextPage.ZIndex = 25
nextPage.Parent = footer
corner(nextPage, 7)
local pageLabel = Instance.new("TextLabel")
pageLabel.Size = UDim2.new(1, -180, 1, 0)
pageLabel.Position = UDim2.fromOffset(90, 0)
pageLabel.BackgroundTransparency = 1
pageLabel.Text = "Page 1 / 1"
pageLabel.TextColor3 = C.muted
pageLabel.TextSize = 12
pageLabel.Font = Enum.Font.Gotham
pageLabel.ZIndex = 25
pageLabel.Parent = footer
----------------------------------------------------------------
-- RESULT STATE
----------------------------------------------------------------
local results = {}
local currentPage = 1
local currentSection = "Overview"
local scanning = false
local function setStatus(text, color)
status.Text = text
status.TextColor3 = color or C.muted
end
local function clearRenderedRows()
for _, child in ipairs(scrolling:GetChildren()) do
if child:IsA("TextButton") or child:IsA("TextLabel") then
child:Destroy()
end
end
end
local function addResult(category, severity, path, detail)
if #results >= MAX_RESULTS_PER_SCAN then
return
end
table.insert(results, {
category = category,
severity = severity or "INFO",
path = path or "",
detail = detail or "",
})
end
local function severityColor(level)
if level == "HIGH" then
return C.danger
elseif level == "MEDIUM" then
return C.warn
else
return C.muted
end
end
local function renderPage()
clearRenderedRows()
local total = #results
local totalPages = math.max(1, math.ceil(total / PAGE_SIZE))
if currentPage > totalPages then
currentPage = totalPages
end
if currentPage < 1 then
currentPage = 1
end
local first = (currentPage - 1) * PAGE_SIZE + 1
local last = math.min(total, first + PAGE_SIZE - 1)
if total == 0 then
local empty = Instance.new("TextLabel")
empty.Size = UDim2.new(1, -10, 0, 72)
empty.BackgroundTransparency = 1
empty.Text = currentSection == "Overview"
and "Choose a scan from the left.\nNothing runs automatically."
or "No results in this section."
empty.TextColor3 = C.muted
empty.TextSize = 14
empty.Font = Enum.Font.Gotham
empty.TextWrapped = true
empty.ZIndex = 24
empty.Parent = scrolling
else
for i = first, last do
local item = results[i]
local row = Instance.new("TextButton")
row.Size = UDim2.new(1, -4, 0, 48)
row.BackgroundColor3 = C.panel2
row.BorderSizePixel = 0
row.AutoButtonColor = false
row.Text = ""
row.LayoutOrder = i
row.ZIndex = 24
row.Parent = scrolling
corner(row, 7)
local sev = Instance.new("TextLabel")
sev.Size = UDim2.fromOffset(72, 18)
sev.Position = UDim2.fromOffset(8, 6)
sev.BackgroundTransparency = 1
sev.Text = item.severity
sev.TextColor3 = severityColor(item.severity)
sev.TextSize = 10
sev.Font = Enum.Font.GothamBold
sev.TextXAlignment = Enum.TextXAlignment.Left
sev.ZIndex = 25
sev.Parent = row
local cat = Instance.new("TextLabel")
cat.Size = UDim2.fromOffset(120, 18)
cat.Position = UDim2.fromOffset(78, 6)
cat.BackgroundTransparency = 1
cat.Text = item.category
cat.TextColor3 = C.accent2
cat.TextSize = 10
cat.Font = Enum.Font.GothamBold
cat.TextXAlignment = Enum.TextXAlignment.Left
cat.ZIndex = 25
cat.Parent = row
local pathLabel = Instance.new("TextLabel")
pathLabel.Size = UDim2.new(1, -16, 0, 18)
pathLabel.Position = UDim2.fromOffset(8, 24)
pathLabel.BackgroundTransparency = 1
pathLabel.Text = item.path
pathLabel.TextColor3 = C.text
pathLabel.TextSize = 11
pathLabel.Font = Enum.Font.Code
pathLabel.TextXAlignment = Enum.TextXAlignment.Left
pathLabel.TextTruncate = Enum.TextTruncate.AtEnd
pathLabel.ZIndex = 25
pathLabel.Parent = row
row.Activated:Connect(function()
pathLabel.Text = item.path .. (item.detail ~= "" and (" | " .. item.detail) or "")
pathLabel.TextWrapped = true
row.Size = UDim2.new(1, -4, 0, 72)
pathLabel.Size = UDim2.new(1, -16, 0, 42)
end)
end
end
countLabel.Text = tostring(total) .. " results"
pageLabel.Text = string.format("Page %d / %d", currentPage, totalPages)
end
local function resetResults(sectionName)
results = {}
currentPage = 1
currentSection = sectionName
sectionTitle.Text = sectionName
renderPage()
end
----------------------------------------------------------------
-- SCANNERS
----------------------------------------------------------------
local function allDescendants()
local list = game:GetDescendants()
return list
end
local function progress(i, total, label)
if i % 500 == 0 then
setStatus(string.format("%s — %d / %d", label, i, total), C.warn)
RunService.Heartbeat:Wait()
end
end
local function scanRemotes(append)
if not append then
resetResults("Remotes")
end
local list = allDescendants()
setStatus("SCANNING REMOTES...", C.warn)
for i, obj in ipairs(list) do
if obj:IsA("RemoteEvent")
or obj:IsA("RemoteFunction")
or obj:IsA("UnreliableRemoteEvent")
or obj:IsA("BindableEvent")
or obj:IsA("BindableFunction")
then
local path = safeFullName(obj)
local sev = riskLevel(path)
if obj:IsA("RemoteEvent") or obj:IsA("RemoteFunction") or obj:IsA("UnreliableRemoteEvent") then
if sev == "INFO" then sev = "MEDIUM" end
end
addResult("REMOTE", sev, path, obj.ClassName)
end
progress(i, #list, "REMOTES")
end
end
local function scanCode(append)
if not append then
resetResults("Client Code")
end
local list = allDescendants()
setStatus("SCANNING CLIENT CODE...", C.warn)
for i, obj in ipairs(list) do
if obj:IsA("LocalScript") then
addResult("LOCAL", "MEDIUM", safeFullName(obj), "LocalScript is replicated to client")
elseif obj:IsA("ModuleScript") then
addResult("MODULE", riskLevel(safeFullName(obj)), safeFullName(obj), "ModuleScript is visible to client")
elseif obj:IsA("Script") then
local rc = safeRead(obj, "RunContext")
if rc and tostring(rc):find("Client") then
addResult("CLIENT SCRIPT", "MEDIUM", safeFullName(obj), tostring(rc))
end
end
progress(i, #list, "CODE")
end
end
local function scanState(append)
if not append then
resetResults("State / Values")
end
local list = allDescendants()
setStatus("SCANNING STATE...", C.warn)
for i, obj in ipairs(list) do
local path = safeFullName(obj)
local ok, attrs = pcall(function()
return obj:GetAttributes()
end)
if ok then
for name, value in pairs(attrs) do
local text = path .. "." .. tostring(name)
addResult("ATTRIBUTE", riskLevel(text), text, valueToString(value))
end
end
local okTags, tags = pcall(function()
return CollectionService:GetTags(obj)
end)
if okTags then
for _, tag in ipairs(tags) do
addResult("TAG", riskLevel(path .. "." .. tag), path, tag)
end
end
if obj:IsA("ValueBase") then
local value = safeRead(obj, "Value")
addResult("VALUE", riskLevel(path), path, valueToString(value))
end
if obj:IsA("Tool") then
addResult("TOOL", riskLevel(path), path, "Client-visible Tool")
end
progress(i, #list, "STATE")
end
end
local function scanInteractions(append)
if not append then
resetResults("Interactions")
end
local list = allDescendants()
setStatus("SCANNING INTERACTIONS...", C.warn)
for i, obj in ipairs(list) do
local path = safeFullName(obj)
if obj:IsA("ProximityPrompt") then
local detail = string.format(
"Action=%s | Distance=%s | Hold=%s",
valueToString(safeRead(obj, "ActionText")),
valueToString(safeRead(obj, "MaxActivationDistance")),
valueToString(safeRead(obj, "HoldDuration"))
)
addResult("PROMPT", "MEDIUM", path, detail)
elseif obj:IsA("ClickDetector") then
addResult(
"CLICK",
"MEDIUM",
path,
"Distance=" .. valueToString(safeRead(obj, "MaxActivationDistance"))
)
elseif obj:IsA("DragDetector") then
addResult("DRAG", "MEDIUM", path, "Client interaction surface")
end
progress(i, #list, "INTERACTIONS")
end
end
local function scanPhysics(append)
if not append then
resetResults("Physics")
end
local list = allDescendants()
setStatus("SCANNING PHYSICS...", C.warn)
for i, obj in ipairs(list) do
if obj:IsA("BasePart") then
local anchored = safeRead(obj, "Anchored")
if anchored == false then
local detail = string.format(
"Massless=%s | CanCollide=%s | CanTouch=%s | CanQuery=%s",
valueToString(safeRead(obj, "Massless")),
valueToString(safeRead(obj, "CanCollide")),
valueToString(safeRead(obj, "CanTouch")),
valueToString(safeRead(obj, "CanQuery"))
)
addResult("UNANCHORED", "MEDIUM", safeFullName(obj), detail)
end
elseif obj:IsA("Constraint")
or obj:IsA("BodyMover")
or obj:IsA("LinearVelocity")
or obj:IsA("AngularVelocity")
or obj:IsA("VectorForce")
or obj:IsA("AlignPosition")
or obj:IsA("AlignOrientation")
then
addResult("PHYSICS CTRL", "MEDIUM", safeFullName(obj), obj.ClassName)
end
progress(i, #list, "PHYSICS")
end
end
local assetProperties = {
Sound = {"SoundId"},
Animation = {"AnimationId"},
Decal = {"Texture"},
Texture = {"Texture"},
MeshPart = {"MeshId", "TextureID"},
SpecialMesh = {"MeshId", "TextureId"},
ImageLabel = {"Image"},
ImageButton = {"Image"},
VideoFrame = {"Video"},
Shirt = {"ShirtTemplate"},
Pants = {"PantsTemplate"},
SurfaceAppearance = {"ColorMap", "NormalMap", "MetalnessMap", "RoughnessMap"},
}
local function scanAssets(append)
if not append then
resetResults("Assets")
end
local list = allDescendants()
setStatus("SCANNING ASSETS...", C.warn)
for i, obj in ipairs(list) do
for className, props in pairs(assetProperties) do
if obj:IsA(className) then
for _, prop in ipairs(props) do
local value = safeRead(obj, prop)
if value ~= nil and tostring(value) ~= "" then
addResult(
"ASSET",
riskLevel(safeFullName(obj)),
safeFullName(obj) .. "." .. prop,
valueToString(value)
)
end
end
end
end
progress(i, #list, "ASSETS")
end
end
local function showRisks()
resetResults("Risk Review")
setStatus("BUILDING RISK VIEW...", C.warn)
local list = allDescendants()
for i, obj in ipairs(list) do
local path = safeFullName(obj)
local sev = riskLevel(path)
if sev ~= "INFO" then
addResult("NAME RISK", sev, path, obj.ClassName)
end
if obj:IsA("RemoteEvent") or obj:IsA("RemoteFunction") or obj:IsA("UnreliableRemoteEvent") then
addResult("REMOTE", "MEDIUM", path, obj.ClassName)
end
if obj:IsA("ModuleScript") or obj:IsA("LocalScript") then
local codeSev = riskLevel(path)
if codeSev == "INFO" then codeSev = "MEDIUM" end
addResult("CLIENT CODE", codeSev, path, obj.ClassName)
end
if obj:IsA("ValueBase") and sev ~= "INFO" then
addResult("STATE", sev, path, valueToString(safeRead(obj, "Value")))
end
progress(i, #list, "RISKS")
end
setStatus("RISK REVIEW COMPLETE", C.ok)
renderPage()
end
local function runSingle(name, fn)
if scanning then
setStatus("SCAN ALREADY RUNNING", C.danger)
return
end
scanning = true
local ok, err = pcall(function()
fn(false)
end)
if ok then
setStatus(name .. " COMPLETE", C.ok)
else
setStatus("ERROR: " .. tostring(err), C.danger)
warn("[AUDIT] " .. tostring(err))
end
scanning = false
renderPage()
end
local function runFullScan()
if scanning then
setStatus("SCAN ALREADY RUNNING", C.danger)
return
end
scanning = true
resetResults("Full Scan")
local ok, err = pcall(function()
scanRemotes(true)
scanCode(true)
scanState(true)
scanInteractions(true)
scanPhysics(true)
scanAssets(true)
end)
if ok then
setStatus("FULL SCAN COMPLETE", C.ok)
else
setStatus("ERROR: " .. tostring(err), C.danger)
warn("[AUDIT] " .. tostring(err))
end
scanning = false
renderPage()
end
----------------------------------------------------------------
-- OVERVIEW
----------------------------------------------------------------
local function showOverview()
resetResults("Overview")
local streaming = safeRead(workspace, "StreamingEnabled")
addResult("SYSTEM", "INFO", "PlaceId", tostring(game.PlaceId))
addResult("SYSTEM", "INFO", "GameId", tostring(game.GameId))
addResult("SYSTEM", "INFO", "JobId", tostring(game.JobId))
addResult("SYSTEM", "INFO", "StreamingEnabled", tostring(streaming))
addResult("SYSTEM", "INFO", "Loaded descendants", tostring(#game:GetDescendants()))
addResult("INFO", "INFO", "Usage", "Select a scan from the left. Nothing runs automatically.")
setStatus("READY", C.ok)
renderPage()
end
----------------------------------------------------------------
-- BUTTON BINDINGS
----------------------------------------------------------------
launcher.Activated:Connect(function()
main.Visible = true
launcher.Visible = false
end)
local function hideMain()
main.Visible = false
launcher.Visible = true
end
-- X and minimize both intentionally hide, never destroy.
close.Activated:Connect(hideMain)
minimize.Activated:Connect(hideMain)
btnOverview.Activated:Connect(showOverview)
btnRemotes.Activated:Connect(function()
runSingle("REMOTE SCAN", scanRemotes)
end)
btnCode.Activated:Connect(function()
runSingle("CLIENT CODE SCAN", scanCode)
end)
btnState.Activated:Connect(function()
runSingle("STATE SCAN", scanState)
end)
btnInteractions.Activated:Connect(function()
runSingle("INTERACTION SCAN", scanInteractions)
end)
btnPhysics.Activated:Connect(function()
runSingle("PHYSICS SCAN", scanPhysics)
end)
btnAssets.Activated:Connect(function()
runSingle("ASSET SCAN", scanAssets)
end)
btnRisks.Activated:Connect(showRisks)
btnFull.Activated:Connect(runFullScan)
btnClear.Activated:Connect(function()
resetResults("Overview")
setStatus("RESULTS CLEARED", C.ok)
end)
prevPage.Activated:Connect(function()
currentPage -= 1
renderPage()
end)
nextPage.Activated:Connect(function()
currentPage += 1
renderPage()
end)
----------------------------------------------------------------
-- HOTKEY
----------------------------------------------------------------
UserInputService.InputBegan:Connect(function(input, processed)
if processed then
return
end
if input.KeyCode == Enum.KeyCode.RightShift then
if main.Visible then
hideMain()
else
main.Visible = true
launcher.Visible = false
end
end
end)
----------------------------------------------------------------
-- SIMPLE DRAG FOR LAUNCHER
----------------------------------------------------------------
do
local dragging = false
local dragStart
local startPos
launcher.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1
or input.UserInputType == Enum.UserInputType.Touch
then
dragging = true
dragStart = input.Position
startPos = launcher.Position
end
end)
UserInputService.InputChanged:Connect(function(input)
if dragging and (
input.UserInputType == Enum.UserInputType.MouseMovement
or input.UserInputType == Enum.UserInputType.Touch
) then
local delta = input.Position - dragStart
launcher.Position = UDim2.new(
startPos.X.Scale,
startPos.X.Offset + delta.X,
startPos.Y.Scale,
startPos.Y.Offset + delta.Y
)
end
end)
UserInputService.InputEnded:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1
or input.UserInputType == Enum.UserInputType.Touch
then
dragging = false
end
end)
end
----------------------------------------------------------------
-- START STATE
----------------------------------------------------------------
showOverview()
main.Visible = false
launcher.Visible = true
print("[AUDIT] v5 loaded. Click the AUDIT button to open the menu.")