WoW Addons: Why Protected Functions and Taint Stop a UI Mid-Fight

By Indie Kings | October 19, 2026

Updated October 19, 2026: World of Warcraft addons are Lua programs that the client loads and runs against a documented API, while protected functions and the taint model stop third-party code from choosing targets or spells. That restriction, which the Warcraft Wiki dates to patch 2.0 in 2006, is the reason a stranger's interface code has been safe enough to install for two decades.

GitHub social preview card for the dnl-gentile olympus-addon repository

Image credit: dnl-gentile/olympus-addon on GitHub, social preview. The repository is used here as an example of a modern addon built on the WoW API.

What an addon is

A World of Warcraft addon is not a separate program. It is a folder of Lua files, XML layout files and a table of contents file that the game client reads at login and executes inside its own process. The Warcraft Wiki's API documentation puts the interface in plain terms: the WoW API is used by Blizzard's Lua user interface itself and is also available to addons and macro scripts, and Blizzard documents it in a bundle the client exposes through the /api command. The same page notes that the game's own FrameXML interface code can be exported from the client.

That last detail matters more than it looks. Addon authors are not reverse engineering a hidden surface. They work against the same interface Blizzard's default action bars, bags and raid frames use, and they can read the shipped source of those frames. The API index on the wiki is organized by the systems that interface touches: action bars, auras, bags, chat, guilds, maps, professions, the auction house, and more, each with named functions and their return values.

An addon still has to be loaded. The client tracks addon state and metadata through calls such as C_AddOns.GetAddOnMetadata, and the index marks some entries with restrictions rather than treating every function as equally callable. Restrictions are the subject of the rest of this piece.

Lua with one documented door

The useful way to picture the setup is a language runtime with a narrow door. Addon code is ordinary Lua, but the game engine and its internal state sit behind the API. If a function is not exposed there, addon code has no documented way to call it. The Warcraft Wiki describes third-party addons as an untrusted source by definition, not as a category that has earned trust through review.

That framing comes from the security model the wiki calls secure execution and tainting. When the interface loads, Blizzard's signed interface code and addons plus their saved variables are treated as secure, while all code and data from third-party addons is treated as tainted. The starting state is not neutral. Third-party code begins on the wrong side of a line drawn by the client.

Being on that side does not block ordinary interface work. An addon can create frames, move them, draw textures, register events and read state the API exposes. What it cannot do is inherit the trust of the code around it.

What the API exposes

The index the wiki maintains is large and ordinary in the way a platform reference is ordinary. Action bar entries read cooldowns and charges. C_ActionBar.GetActionCooldown returns cooldown information for a slot, and C_ActionBar.GetActionCharges returns charge information. Auras, unit information, containers, quests, maps and chat each have their own namespace with getters, setters and events.

Some entries carry markers that show the boundary without any prose. In the index, C_AuctionHouse.PlaceBid and C_AuctionHouse.PostItem are tagged as requiring a hardware event, and several auction house query and search calls carry a no script marker. Those tags describe who may call a function and under what conditions, not merely what it does.

Communication between players is part of the surface too. C_ChatInfo.SendAddonMessage lets an addon send a prefixed message over a chat channel, and C_ChatInfo.RegisterAddonMessagePrefix claims that prefix. This is how a census addon, a raid tool or a group finder talks to other clients without a server of its own. It is also a reminder that the sandbox governs game actions, not everything an addon can say.

The wiki's index is marked current as of PTR patch 12.1.5, build 69594, dated August 28, 2026. The date is worth stating because it separates a documented platform from a frozen one: the surface changes, and the documentation tracks it.

Protected functions

A protected function is one that can only be called successfully from a secure execution state, per the wiki's terminology. Targeting a unit, casting a spell and moving a character sit in that category. The protection is not a convention that addons are asked to respect. It is enforced by the client, and a call from tainted code fails.

The wiki dates the model to patch 2.0 and calls it a cornerstone of the API ever since. That patch arrived in 2006, and the wiki quotes a blue post from October 6 of that year announcing the change: addons and macros would no longer be capable of casting spells or targeting units. A follow-up clarification in the same section is narrower and more useful. Addons would still be able to cast a spell with user interaction, but they would not be able to use logic to pick the spell or the target.

That distinction is the whole design. Automation was not removed from the interface; decision making was moved back to the player. An addon may build a button, label it, and cast when a human presses it. It may not watch a cooldown, choose a target and fire on its own.

ActionPossible for addon code aloneWhat the Warcraft Wiki says
Choose a target and cast at itNoThe 2006 announcement quoted by the wiki states addons and macros "will no longer be capable of casting spells or targeting units".
Cast a spell after a player clicksYesThe clarification says addons can still cast "with user interaction", but cannot use logic to pick spells or targets.
Display the spell a player should press nextYesThe wiki notes an addon can suggest a spell on screen but cannot make the decision for the player.
Call a protected function from tainted code in combatNoProtected functions refuse to operate when they detect an insecure execution path.
Run extra code after a secure function without tainting itYeshooksecurefunc post-hooks a secure global so the addon's function runs afterward.
Resize or reconfigure a protected frame during combatNoProtected frames must be created and programmed out of combat using preset attributes.
Read a cooldown or charge countYesC_ActionBar.GetActionCooldown and C_ActionBar.GetActionCharges return that data in the API index.
Post an auction or place a bidOnly through a hardware event pathC_AuctionHouse.PlaceBid and C_AuctionHouse.PostItem are tagged as hardware event functions in the index.

Taint, the honey that sticks

Taint is the wiki's name for the marker that follows data and code from an untrusted source. The page's own analogy is sticky honey: addon code is sticky, anything it touches becomes sticky, and Blizzard's clean code becomes sticky if it handles something an addon made. A protected function called while the execution path is sticky fails.

The rules are granular. All Lua values and references can be tainted, including local variables, globals, table keys and table values. New values inherit the taint of the path that created them. Reading a secure value taints the result but leaves the original clean. Reading a tainted value taints both the result and the path. Writing a global gives the new value the taint of the path that wrote it. Function closures can carry taint too, and executing one applies it to the current environment.

Persistence is the part that surprises people. Per the wiki, taint remains for the rest of the session until the player relogs or reloads the interface. It is not scoped to the frame that caused it, and it is not cleared by closing a window. Once the path is dirty, every protected call that runs through it can fail.

Why a UI stops mid fight

A UI that suddenly refuses to act is usually a taint symptom, not a broken install. The addon touched a secure value, passed tainted data into a function Blizzard's interface later calls, or hooked something in a way that spread its state into a protected path. In combat, the client stops trusting the call and the action does nothing.

The error message is a clue rather than a verdict. Because each addon's honey has its own flavor, the wiki says the error handler tests the taint and names the addon it blames. That is why a failure can point at an addon the player installed months ago rather than at the action that visibly failed.

Two sanctioned tools exist for reading and extending secure behavior without spreading taint. hooksecurefunc post-hooks a secure global function, running the addon's code after the original with a copy of the same arguments. frame:HookScript does the same for a frame script. Neither replaces the secure behavior. They observe it, which is the only relationship the model allows.

The wiki also gives addon authors a timing rule: check InCombatLockdown() before creating secure frames, setting their attributes or reconfiguring them. Protected frame restrictions propagate to parents and to frames they are anchored to, so moving an unrelated window during a fight can lock something the author never meant to touch.

Secure templates and the human click

The client does not leave addons with nothing. Patch 2.0 introduced protected frames and the SecureTemplates family; patch 3.0 expanded the capability with SecureHandlers, per the wiki. These are XML templates that define secure script handlers and usually create protected frames. An addon can inherit one, and the handlers it defines remain secure unless the inheriting frame overrides them.

The catch is configuration. Secure templates are set up with frame attributes, and those attributes can only be set outside combat. Even the logic is bounded to a narrow set of rules that keep a human in the loop. Once combat starts, the game manages showing, hiding, sizing and positioning protected frames according to whatever was configured earlier.

The wiki's example is the clearest illustration of what changed. Before the model, an addon could pick a spell, and even a spell rank, after any left click. After patch 2.0, an addon can cast one spell after a left click and another after a right click, but the player must decide which button to press. Information can still be shown. The decision cannot be made for them.

A protected frame cannot be made unprotected once declared, so the constraint is structural. That is why action bars, unit frames and cast bars built by addons look the way they do: a secure shell with fixed behavior and a large amount of non-secure decoration around it.

Classic inherits the same rules

Players sometimes assume that a Classic client restores the wilder addon behavior of 2004. It does not. The wiki states that World of Warcraft: Classic uses the modern API, including secure execution and tainting, so addons cannot perform the automation that was technically possible in vanilla.

That fact reframes every classic era addon conversation. A 2004 style client with a 2026 addon culture is not an accident of porting. The restriction travels with the code, and the ecosystem that grew around it travels too.

Why restriction built the ecosystem

Here is the counterintuitive part. Addon installation can be casual because the client already assumes every addon is hostile. Nothing in the model requires a review board to bless a UI package, a publisher to sign it or a curator to vouch for the author's intentions. The sandbox has priced in the worst case in advance.

An addon that misbehaves can break the interface, spam a chat channel or waste a player's time. What it cannot do is take over the character. The cost of a bad addon is bounded by the same model that stops a good one from automating combat, and that bound is what lets players try a stranger's work and remove it without consequence.

Restriction also made the ecosystem legible. Because the API is documented and the interface code is exportable, knowledge accumulates in public. A developer can read how Blizzard built a raid frame, copy the pattern, and ship a replacement that the client still trusts to be clicked. The sandbox is the contract that makes that exchange possible across two decades of patches.

The model is not a guarantee of quality. It is a guarantee about reach. Taint and protected functions decide what code can touch, not whether the result is good, and a poorly written addon can still ruin a raid night. The claim here is narrower and, for anyone deciding whether to install a stranger's UI, more relevant: the dangerous part was closed off before the addon was written.

Our take

The WoW addon sandbox is the most successful piece of user generated software policy in games, and it succeeded by saying no. Blizzard gave away the interface and kept the combat decisions, then documented the boundary well enough that mod authors could build a career on the permitted side. Twenty years later, that trade still looks better than the alternative: a permissive client where every install is a trust fall, and where the good addons never get the benefit of the doubt.

FAQ

Can a WoW addon cast spells for me?
Not by deciding. Per the Warcraft Wiki's account of the 2006 change, addons can still cast with user interaction, but they cannot use logic to pick the spell or the target. A secure button can fire when you click it, and nothing in addon code can choose that click for you.

What does "tainted" mean in a WoW error message?
It means the execution path touched data or code from a third-party addon. The wiki treats all addon code and its saved variables as tainted from load, and a protected function called through a tainted path refuses to operate.

Why does my interface break only in combat?
Combat is when protected functions and protected frames enforce their restrictions. A frame or value that worked while you were standing still can fail the moment the client decides the call is insecure, and the failure often surfaces at the worst moment.

Does reloading the UI clear taint?
Yes. The wiki says taint remains for the rest of the session until the player relogs or reloads the interface. That clears the marker, but it does not fix the addon that reintroduced it, so the same failure can return on the next pull.

Do addons run as separate programs?
No. The client loads Lua and XML from the addon folder and executes it inside the game, so there is no separate application to install, update or close. What the addon can reach is decided by the API the client exposes to it.

Do addons work the same way in Classic?
Yes. The wiki states that Classic uses the modern API with secure execution and tainting, so the automation that was possible in vanilla is not available on a Classic client.

Bottom Line

The WoW addon model is a restriction engine, not an open plugin system. Addon code is Lua running inside the client, it reaches the game only through a documented API, and it is treated as tainted from the first line. Protected functions and secure templates keep target and spell decisions with the player, while hooksecurefunc and HookScript let addons observe secure behavior without owning it. That boundary, in place since patch 2.0, is why installing a stranger's interface is a normal thing to do rather than an act of faith.

Sources

Related: WowUp Keeps Every Addon Updated On Windows Mac Linux | Olympus Guild Addon for WoW Forever: Census and Layer Hop in 5 Steps [2026]

Share