ERC-20 allowance
The allowance is the running budget that an ERC-20 token records for each (owner, spender) pair: how many of the owner's tokens that spender is still permitted to pull. It is stored as a nested mapping, allowance[owner][spender], a uint256. The owner sets it with approve, anyone can read it with allowance(owner, spender), and each successful transferFrom by the spender subtracts the moved amount from it. This two-step approve-then-transferFrom dance is how contracts pull tokens, since they cannot push tokens out of an account they do not own.
The famous flaw is the approval race condition. Suppose Alice has approved Bob for 100 tokens and wants to lower it to 50. She sends approve(Bob, 50). If Bob is watching the mempool, he can front-run that update with a transferFrom of the old 100, then, after her approve lands, spend the new 50 — moving 150 in total, more than Alice ever intended for any single window. The standard's approve simply overwrites the value, so it offers no protection by itself.
Mitigations have evolved. The classic advice is to first set the allowance to zero, wait for that to confirm, then set the new value, so there is no live old allowance to exploit. Libraries added increaseAllowance and decreaseAllowance to change the budget by a delta rather than overwriting it (OpenZeppelin later deprecated these in v5 as the race is rarely exploitable in practice and permit is preferred). Signature-based approvals via ERC-2612 permit sidestep the separate approve transaction entirely.
The race needs the spender to be malicious and quick, and you to lower a non-zero allowance to another non-zero value. Setting to zero first, or using permit, removes the window.