mutated × shared — the answer changes between runs
Out-of-Order Async Completion
Two requests write one variable; whichever resolves last wins — and completion order isn't the order you asked in.
01the recipe
In the wild
compound ofvar / let / mut DeclarationsCWE-563Async IO MisuseCWE-662 Improper SynccompoundCWE-362 Race ConditionCWE-696 Bad Operation Order
example.js
// SMELL: two requests write one variable; last to resolve wins, not last asked.
// (var/let/mut x async I/O misuse)
let results;
async function search(q) {
results = await fetchJSON(q); // a slow early query can land AFTER a fast late one
render(results); // -> stale results overwrite the fresh ones
}
// RIGHT: tie the write to the latest request; drop out-of-order completions.
let latest = 0;
async function search(q) {
const seq = ++latest;
const r = await fetchJSON(q);
if (seq === latest) render(r); // ignore anything but the newest queryAsync completions arrive in an order the code never fixed; a mutable, shared 'results' lets whichever finishes last win. Type fast and an earlier request's answer can clobber the one you are looking at.
// observed
race: a slow 'a' lands after 'ab' and overwrites it right: stale responses dropped; newest query always wins
02weakness catalog
Mapped weaknesses (CWE)
On its own, this defect is catalogued by MITRE as one or more of these weaknesses. The exploitable vulnerability usually appears only when it chains or combines with another.