
Why the MW3 "godmode class" exploit works
If you played Modern Warfare 3 in 2012 you might remember “Swag.Class”: a custom class that made you invisible, let you move during the pre-match countdown, and left you unable to die properly. Players who shot at you could even get kicked. There is no overflow and no memory corruption. It is a script design flaw, and this post walks through it, step by step.
The short version
A custom class that uses the Specialist strike package stores a kill cost for each of its three specialist streaks. Nothing checks those numbers. One of the spawn scripts counts from 0 up to the largest cost, one integer at a time. A huge cost makes that loop run for millions of iterations. The script VM has a 5 second watchdog on loops, and when it fires it silently kills the running thread and every parent thread. The thread it kills is the player spawn, so the rest of the spawn never happens.
The chain, step by step
-
Unvalidated data. Each custom class has
specialistStreakKills[0..2], three 4-byte integers in the player’s stats. The player controls their own stats, and the server uses the copy uploaded when you connect. The server’s class check validates perks, weapons and streak names by string, but never these numbers. -
The cost is just a number.
getStreakCostreturns that value for a Specialist custom class. Script only compares it with your current kill count, so a huge or negative value looks fine there. -
A loop that visits every integer.
setKillstreaks, called fromgiveLoadout, builds a sparse array keyed by cost and then rebuilds it in order:for (streakIndex = 0; streakIndex <= maxVal; streakIndex++)if (!isDefined(killStreaks[streakIndex])) continue;It visits every integer up to the largest key, not only the keys that exist, so its runtime grows with the highest cost. Normal classes use costs below 30, so it never mattered.
-
A cap by accident. Integer array keys in the VM are only 24 bits wide. The largest key that stays positive is 8,388,607, so the useful maximum is about 8.3 million iterations. A larger cost wraps to a negative key and the loop barely runs. That is why the guides said values like 34 to 127 in the third byte of the number work, and anything higher does nothing.
-
The watchdog. Every script loop ends with a backward jump (
OP_TIMEOUT_JUMP). If the thread has been running for more than 5000 ms, the VM does not raise a script error. It kills the current thread and walks up through every parent, killing each one. In a release build nothing is logged. -
The thread that dies is the spawn.
giveLoadoutruns inside the player’s spawn thread. Killing it and its parents stops the spawn partway through.
Symptoms and where they come from
| Symptom | Likely cause |
|---|---|
| Countdown freezes | Script runs on the server frame, so a long loop blocks the whole game until it finishes or the watchdog fires. |
| Invisible | The model and body setup after giveLoadout never ran. |
| Can move during the countdown | The movement lock is applied by spawn code that never ran. |
| Players who shoot your head get kicked | The entity has no head bone, so the aim target lookup (AimTarget_GetTagPos) hits a fatal error for the shooter. |
| Seems dead only when shot, but isn’t | Health was never set up by the missing spawn code. |
| Still earns streaks and ammo | Those systems run in separate threads started earlier, which survive. |
Why it depends on your machine
The kill only fires if the loop takes longer than 5 seconds. The maximum loop is about 8.3 million iterations. On an Xbox 360 or an older PC that takes longer than 5 seconds, which fits the old advice that “34 is the minimum, 45 is good” and the report that 0x6B worked on an older PC client. On a modern CPU the loop finishes in under 5 seconds: the spawn just freezes for a moment, then carries on normally.
What I tested
Tested:
- Writing the third kill cost into a private-match Specialist class and spawning: the value reaches the script and the loop runs. At 8.3 million iterations on my machine the spawn froze briefly but completed.
- Values above 0x7FFFFF (such as 255 in the third byte, or 2 billion) do nothing, because the array key wraps negative.
- With the watchdog limit lowered to 500 ms in a debug build, the thread is killed (the log shows the kill), and the player spawns invisible and can move during the countdown.
![]()
How it could have been prevented
- Reject out-of-range kill costs in the server’s class check.
- Cap the cost that
getStreakCostreturns. - Avoid the dense loop: sort the keys that exist instead of counting up to the largest one.
- Make the watchdog raise a visible script error instead of silently killing the parent chain.
Where the evidence comes from
The Xbox 360 and PC script bytecode have the same getStreakCost and setKillstreaks logic. The class layout (98-byte class entries, kill costs at +82, +86 and +90) matches the offsets used by a known cheat for this exploit. The behaviour of the watchdog comes from the VM code in the game executable.