Secure Execution and Tainting
The User Interface API mandates human decision-making, particularly in combat, by protecting many functions from insecure or tainted use. This security model was largely introduced in Patch 2.0 and has been a cornerstone of the API ever since.
When WoW begins executing Lua code, the execution starts off 'secure' and able to run protected functions in all situations. Execution remains secure until it encounters 'taint' - which is an indicator that a function or object came from an untrusted source (AddOn or /script). The basic idea is that execution becomes 'tainted' as soon as it reads data or code introduced by a third party, and any new data written by already-tainted execution becomes also tainted. If an AddOn spreads taint to important game functions, it will prevent them from working (especially in combat). Taint remains for the rest of the game until the player relogs or reloads the interface, which can be crippling because protected functions will refuse to operate if they detect a potentially insecure execution path.
When the UI first loads, all code and data from Blizzard signed FrameXML and AddOns (plus their saved variables) is secure, and all code and data from third-party AddOns (plus their saved variables) is tainted.
What can be tainted?
All Lua values and references can be tainted - local variables, global variables, table keys, table values:
- When new values are created (e.g. local x = 2) then they inherit the current taint of their execution path.
- When code accesses secure values, the resulting value will be tainted by the current execution path (but the original value remains clean).
- When code accesses tainted values, the resulting value will remain tainted and the execution path is also tainted.
- When code sets global values, the resulting value has the taint of the execution path.
Function closures can also be tainted, executing a function closure applies its taint to the current environment.
Taint is inherent to third-party code, but the API provides two powerful functions to avoid spreading taint to protected game functions:
- hooksecurefunc(["table"], "name", func)
- Addons can 'post-hook' a secure global function, inserting their own custom function to be executed after the original. It receives a copy of the same arguments the original did, but executes afterward to prevent tainting the original.
- frame:HookScript("handler", func)
- Similar to SetScript() but the custom function is only executed after others; similarly receiving the same arguments but not spreading taint to already-done execution.
Protected frames and secure templates
WoW 2.0 also introduced a new Frame concept, protected frames, which can bypass interactivity restrictions during combat. However, the caveat is that these must be created and pre-programmed while out of combat using pre-defined attributes. Once combat begins, the game will manage showing, hiding, sizing and positioning the frames in accordinance with whatever attributes had been previously set. The attributes allow for some logic, but limited to a narrow set of rules that ensure practical human involvement. Notwithstanding, Secure code is a special case that may bypass these restrictions for additional (but still limited) functionality in combat.
Once a frame has been declared protected it cannot be made unprotected, and protection is generally inherited from specially designed templates such as SecureTemplates (basic capability introduced in Patch 2.0) and SecureHandlers (expanded capability introduced in Patch 3.0).
Control restrictions on protected frames are also applied to their parents and any frames they are anchored to. This is important when anchoring a protected frame to another normally non-protected frame, as it can lead to unexpected and often undesired behavior. This propagation is temporary, and re-anchoring or re-parenting the frame out of combat can release the restriction.
Protected frames are important because they form the basis of the Blizzard action and spell buttons, but also because they allow for some new secure button templates. Since normal AddOn code is tainted, it cannot change targets or perform actions directly, however WoW 2.0 contains a number of secure templates which can be inherited by AddOn code. These secure templates provide one or more secure handlers, usually OnClick, that use frame attributes to perform actions. When a secure template is inherited then any handlers it defines remain secure unless they are overridden by the inheriting frame (or another template).
The secure templates are configured using frame:SetAttribute() methods pertinent to each template, but only outside combat. AddOns should check InCombatLockdown() before creating secure frames, setting their attributes, or reconfiguring their attributes.
Since there are a number of similar concepts at work here, the terminology can be confusing, here's a summary of the common terms and their meanings:
- Secure generally means 'without taint'.
- Secure code refers to either an untainted current execution or an untainted function.
- Values/References/Parameters are sometimes referred to as 'clean', this means the same as 'secure'.
- A protected function is one that can only be successfully called from a secure execution state.
- A protected frame is one that is locked down during combat.
- A protected method is one that cannot be successfully called on a protected frame from a tainted execution state during combat.
- Secure templates are simply XML templates that define secure script handlers, they usually also create protected frames.
Impact on Gameplay
Secure execution profoundly limited what addons could do beginning with Patch 2.0, and was widely perceived as necessary to protect gameplay from cheating. Before this security model, addons were capable of vastly autotating gameplay making by choosing who to target and what spells to cast.
For example, addons might now cast a certain spell in response to left-click, and another spell in response to right-click. Humans would decide which of the two spells were more appropriate, not the addon, even though the addon could suggest to the human which was more appropriate (but not decide for the player).
World of Warcraft: Classic uses the modern API, including secure execution and tainting. Consequently, addons cannot perform the blatantly harmful automation in classic that was technically possible in Vanilla.