Hello! I’m currently at a loss for words. It seems like Roblox added some kind of plugin signing feature at some point making it impossible to load BuiltInPlugins and StandaloneBuiltInPlugins. This makes it impossible for me to modify their functionality, and several of my old projects (which I currently want access to) are completely obsolete. RobloxStudioModManager’s template mods also do not function without BuiltInPlugins. What should I do? Can I even do anything without uploading a bunch of plugins to Roblox?
BuiltinPlugins gained elevated privileges similar to CoreScripts, so they are signed to prevent arbitrary usage of sensitive APIs. If you want to modify a builtin, you should be able to copy or move it to the plugins folder, but you may also have to remove any uses of such APIs if you don’t want it to throw errors.
Do they have elevated privileges above CoreScripts in any cases? My current solution is actually to modify core scripts, but if they eventually become signed for the same reasons I’m going to be extremely disappointed as I’ve used Core Script modifications so much. Originally it seemed that the goal of studio was to be easily moddable and changeable, but it seems like that philosophy might be shifting away.
Here’s a table describing permissions. The last time I checked it was some months ago, so it could be out of date.
Context\Identity | # | CoreScript (3) | BuiltinPlugin (6) | Command (4) | Plugin (5) | Script (2) |
---|---|---|---|---|---|---|
None | 0 | |||||
RobloxPlaceSecurity | 2 | |||||
PluginSecurity | 1 | |||||
LocalUserSecurity | 3 | |||||
RobloxScriptSecurity | 5 | |||||
RobloxSecurity | 6 | |||||
NotAccessibleSecurity | 7 |
Unfortunately, because builtins are now signed, it’s more difficult to verify their permissions. Even so, here’s the script I used:
(function()
local tests = {
{"NotAccessibleSecurity", function() -- 7
game:GetService("Chat").LoadDefaultChat = false
end},
{"RobloxSecurity", function() -- 6
local p = game:GetService("Players"):FindFirstChildOfClass("Player")
if p ~= nil then
p:GetGameSessionID()
else
local _ = game:GetService("StudioData").SrcPlaceId
end
end},
{"RobloxScriptSecurity", function() -- 5
game:GetService("HttpService"):GetHttpEnabled()
end},
{"LocalUserSecurity", function() -- 3
Instance.new("Script"):GetHash()
end},
{"PluginSecurity", function() -- 1
game:GetDebugId()
end},
{"None", function() -- 0
game:IsA("Instance")
end},
}
local results = {}
local bits = ""
for k, v in pairs(tests) do
local result = string.format("%-21s : ", v[1])
if type(v[2]) == "function" then
local ok, err = pcall(v[2])
if ok then
if err ~= nil then
result = result .. "----"
bits = bits .. "-"
else
result = result .. "Okay"
bits = bits .. "1"
end
else
local c = true
if type(err) == "string" then
local got, want = err:match("^The current identity %((.*)%) cannot .* %(lacking permission (.*)%)$")
if got and want then
result = result .. string.format("Fail (%s!%s)", got, want)
c = false
end
end
if c then
result = result .. "Fail"
end
bits = bits .. "0"
end
else
result = result .. "----"
bits = bits .. "x"
end
table.insert(results, result)
end
table.insert(results, 1, "---- Permissions test:")
table.insert(results, string.format("---- %s for identity", bits))
printidentity(table.concat(results, "\n"))
end)()
The raw results:
Script:
------ Permissions test:
--NotAccessibleSecurity : Fail
--RobloxSecurity : Fail (2!6)
--RobloxScriptSecurity : Fail (2!5)
--LocalUserSecurity : Fail (2!3)
--PluginSecurity : Fail (2!1)
--None : Okay
------ 000001 for identity 2
CoreScript:
------ Permissions test:
--NotAccessibleSecurity : Fail
--RobloxSecurity : Fail (3!6)
--RobloxScriptSecurity : Okay
--LocalUserSecurity : Okay
--PluginSecurity : Okay
--None : Okay
------ 001111 for identity 3
Command:
------ Permissions test:
--NotAccessibleSecurity : Fail
--RobloxSecurity : Fail (4!6)
--RobloxScriptSecurity : Fail (4!5)
--LocalUserSecurity : Okay
--PluginSecurity : Okay
--None : Okay
------ 000111 for identity 4
Plugin:
------ Permissions test:
--NotAccessibleSecurity : Fail
--RobloxSecurity : Fail (5!6)
--RobloxScriptSecurity : Fail (5!5)
--LocalUserSecurity : Fail (5!3)
--PluginSecurity : Okay
--None : Okay
------ 000011 for identity 5
BuiltinPlugin:
---- Permissions test:
NotAccessibleSecurity : Fail
RobloxSecurity : Fail (6!6)
RobloxScriptSecurity : Okay
LocalUserSecurity : Okay
PluginSecurity : Okay
None : Okay
---- 001111 for identity 6
Interesting… It appears that BuiltInPlugins have a level under CoreScripts, but above Plugins, so I have no idea why Roblox has then chosen to sign them, but not also sign CoreScripts if they have security concerns. It also appears that creating a plugin (with PluginManager) from within a CoreScript now causes an infinite hang (thus breaking even more of my code), however, doing so anywhere else does not. Well, I’m really unhappy with the signing behaviour, and its broken a ton of my code. Disappointing.
There are a few FFlags which you can disable to disable plugin signatures:
DoNotLoadUnverifiedBuiltInPlugins
VerifyBuiltInPlugins
BuiltInPlugins have LocalUserSecurity access (was able to call DebuggerManager), and their identity is 6, not 5. (And Plugins have identity 5)
I can’t believe I didn’t think of setting FFlags! (Seems like it’d be common sense for me based on the amount of FFlag editing I do) This is actually exactly what I’m looking for as I’m creating something to go alongside Roblox studio mod manager, so I can simply change those flags how I’d like to use them. I very much so hope that Roblox does not intend to remove these flags in the future. Thank you for finding these.
I got the identity numbers swapped. This has been corrected. I’ve also updated the table to reflect the current permissions.
well they removed these flags ):