One instance of a race condition found by a security researcher (Egor Homakov) resulted in essentially unlimited money on Starbucks gift cards. How did it happen?
The exploit took advantage of the way funds were transferred between gift cards. The server-side logic for transferring funds between accounts went something like this:
1. Check balance on card 1.
2. If sufficient funds, increment funds in card 2.
3. Decrement funds in card 1.
The above steps were programmed to happen synchronously (one step at a time), however these actions were actually performed in a multi-threaded asynchronous environment.
To be clear, most modern computing environments are multi-threaded and asynchronous (even when using PHP — more on that later). So how does one exploit this race condition?
Simple: send a ton of requests for this function at the same time, thus creating a high probability that events would occur simultaneously. For example, it may result in the following execution logic:
1. 5 threads check the balance on card 1 (let’s say it’s $5).
2. 5 threads find that the balance is sufficient, and so they increment card 2 by $5, resulting in a total balance of $25.
3. 5 threads each try to decrement the funds in card 1 by $5, however the card can’t go below $0, thus 4 of the threads fail.
Wallet 2 has now gained $25 and wallet 1 has lost only $5.