If you’ve been around Roblox long enough, chances are that you’ve come across members of the API that you can’t access or use and seen phrases like ‘LocalUserSecurity’ or ‘PluginSecurity’ on the wiki. There’s not much documentation for what these things are or how they function, so I thought I would put together a thread about it. If you’re a returning developer and you have working knowledge of normal identities and security tags, this may be a review, but hopefully it will answer some questions or clear up problems.
What is a normal identity?
Every script run in Roblox, whether it be a plugin, a LocalScript, or a CoreScript, all have a level of access that’s assigned to them that determines what they can do. This level is called a normal identity. These identities exist to prevent people from maliciously misusing sensitive APIs and changing things they shouldn’t. Normal identities on Roblox can be gotten by calling the global function printidentity
in any Lua environment. This prints a number version of these identities that can be used for reference.
Here’s a table of them by source:
Source | Identity |
---|---|
Script | 2 |
LocalScript | 2 |
ModuleScript | Varies* |
CoreScript | 3 |
Command Line | 4 |
Run Script | 4 |
Plugin | 5 |
*ModuleScripts run at the identity they are required at |
From the above table you may expect that plugins have the highest permissions available as their identity is the highest. That is not the case. Of those things, CoreScripts actually have the highest overall permissions. The number associated with identities is arbitrary and has no meaning beyond what it’s associated with.
Why do I care?
As I said earlier, each normal identity determines what Roblox API and properties can be accessed and changed. If you’re coding a normal game, there’s a good chance this won’t matter to you unless you’re on the developer hub or messing around with studio’s settings. If you’re a veteran developer and are interested in knowledge for it’s own sake or in making plugins (or even messing with the CoreScripts!) it’s probably important to know what can do what though. There’s also a chance you’ll run into a weird error eventually in your time as a developer and this will help you diagnose and solve this error better.
This error is, simply, The current identity (X) cannot Y (lacking permission Z)
, where X is the normal identity of the script executing the code, Y is a description of what’s being attempted, and Z is a number that indicates what permission is necessary to access these things. Rather than explaining what’s wrong with this error or why it may be confusing, I’ll provide some examples.
Using the code game.Players.Dekkonot.Name = "foo"
in a Plugin
Using the code game.Players.Dekkonot.Name = "foo"
in the Command Line
Using the code: game:GetService("CSGDictionaryService"):GetChildren()
in the Command Line
Using the code game:GetService("ScriptContext"):AddCoreScriptLocal("foo", workspace)
in the Command Line
If you think it looks like the permission numbers are entirely seperate from the actual normal identities, you’d be right. This is where security tags come in.
Security Tags
Without overcomplicating things or going too in-depth, security tags are flags on API members and Instances that indicate what permissions are needed to access them. After doing some analysis on the API dump generated by studio, it can be found that 5 security tags exist, not counting those that have no security: LocalUserSecurity, PluginSecurity, RobloxScriptSecurity, NotAccessibleSecurity, RobloxSecurity
If some testing is done, it can be found out that each normal identity can access API members with specific flags on them. A list of them is here:
Normal Identity | Accessible Security Tags |
---|---|
2 | |
4 | LocalUserSecurity, PluginSecurity |
5 | LocalUserSecurity, PluginSecurity |
3 | LocalUserSecurity, PluginSecurity, RobloxScriptSecurity |
Noticably absent from this table is RobloxSecurity and NotAccessibleSecurity. NotAccessibleSecurity is self-explanatory as it means that the API member literally can’t be accessed by scripts, but RobloxSecurity is a bit more complicated. I’ll get back to that at the end of the post. |
In addition to having string names like ‘LocalUserSecurity’, each security tag appears to have a number associated with it that shows up in errors. After some testing it looks as though the relation is this:
Security Tag | Permission Level |
---|---|
None | |
LocalUserSecurity | 3 |
PluginSecurity | 1 |
RobloxScriptSecurity | 5,1 |
RobloxSecurity | 6 |
NotAccessibleSecurity | ??? |
As you can see by the ‘???’, I cannot actually confirm what, if any, permission level NotAccessibleSecurity has. This will probably never come up because it only occurs on 3 API members (that it’s listed on anyways). I also have no idea why RobloxScriptSecurity has two permissions associated with it. |
This explains what the permission numbers mean, but it fails to account for a few cases. Namely, it fails to explain the locking of specific instances (CSGDictionaryService, AnalyticsService, etc.) and the locking of Player’s Name properties. The former however is easily explained with the RobloxLocked property. This property simply sets whether an Instance (and its descendants) can be accessed. There appear to be two levels of RobloxLocked, though that is purely based on observation and should not be taken as fact: those set to prevent normal scripts from accessing things and those set to prevent all access to something. Examples of the first type include the CoreGui, which is inaccessible to normal scripts but is accessible to everything else. Examples of the second include the CSGDictionaryService, which is inaccessible to all levels.
The latter case, Player names being locked, appears to be hardcoded in, as it generates an error that is unique from other restricted properties. A comparison can be seen in the screenshots earlier.
RobloxSecurity
As promised, here’s an explanation of the RobloxSecurity security tag, as it appears to be an anomaly in that no threads can access those API members regardless of the identity. That’s because members with this security tag are meant soley for internal use, and are thus heavily restricted. According to the most recent API dump, there are exactly 6 members of the API with this security tag. Of them, only 2 are actually accessible (Player::GetGameSessionID and Player::SetUnder13). I did not verify what identity is required to access members tagged with this security, but if the past is anything to go on, it would require an unrestricted thread, which means it had an undefined context identity. This generally comes in the form of 7 (this is where the infamous term ‘level 7’ comes from when talking about exploits), but it could be any undefined number (1, 6, 0, etc.). It’s recommended you don’t think too much about this because these API members have no practical use to developers and in fact cannot be used by them anyways.
In Conclusion
Roblox’s normal identity system isn’t documented in an up-to-date manner anywhere, although it’s actually rather simple once you look into it. This thread was prompted because I realized how weird the errors were and how the identity numbers didn’t line up with the permission numbers. It is my hope that I’ve educated a few people on the subject as well as provided a more up to date explanation on the security and normal identitity systems for Roblox. If you have any questions, or think I’ve gotten something wrong please let me know, either in a reply to this thread or in a PM.
Additional Info Available Here
This script was used to test the normal identities and what security tags could be accessed by them. Normal Identity/Security Test - Pastebin.com
To test CoreGuis, I simply used a CoreGui override. More information can be provided on this if someone asked.