Back to Articles

Racer: The 128-Line Tool That Found a Starbucks Vulnerability

[ View on GitHub ]

Racer: The 128-Line Tool That Found a Starbucks Vulnerability

Hook

A security researcher once bought unlimited Starbucks drinks with a single gift card by exploiting a race condition. The tool that makes finding these vulnerabilities trivial is just 128 lines of code.

Context

Race conditions are the silent killers of web application security. They lurk in checkout flows, voucher redemption systems, and anywhere state changes without proper locking. The classic scenario: a user has one gift card credit, but by sending five simultaneous redemption requests, the application processes all five before any can mark the credit as used. Traditional security testing tools struggle here because reproducing race conditions requires precise timing—requests must arrive at the server within microseconds of each other to slip through validation logic before database commits happen.

Before Racer, testing for race conditions meant either writing custom scripts with async libraries, wrestling with Burp Suite's extensions, or manually coordinating multiple browser windows. These approaches required significant setup time and technical expertise. Security researcher Egor Homakov created Racer to collapse this barrier entirely: install a Chrome extension, click once, and watch as your HTTP request gets replayed five times in parallel from a proxy server you control. It's deliberately simple, almost crude in its approach, but that simplicity is exactly why it works.

Technical Insight

Clicks capture button

Arms listener

Makes HTTP request

Captures request details

headers, cookies, body

Forwards complete request

Sends 5 parallel

identical requests

Race condition responses

User Browser Action

Chrome Extension

sniffer.js

Armed Listener

3-second window

Node.js Proxy Server

racer.js

Target Application

System architecture — auto-generated

Racer's architecture is a masterclass in doing one thing well. The system has two components: a Chrome extension (sniffer.js) that intercepts browser traffic, and a Node.js server (racer.js) that performs the actual parallel request replay. When you activate the extension, it arms a listener that captures the next HTTP request within a three-second window, then forwards the complete request—headers, cookies, authentication tokens, and all—to your proxy server.

The Chrome extension code is remarkably straightforward:

chrome.webRequest.onBeforeRequest.addListener(
  function(details) {
    if (armed && Date.now() - armedTime < 3000) {
      chrome.tabs.query({active: true}, function(tabs) {
        chrome.tabs.sendMessage(tabs[0].id, {
          action: "capture",
          request: details
        });
      });
      armed = false;
    }
  },
  {urls: ["<all_urls>"]},
  ["requestBody"]
);

The three-second window is critical—it gives you just enough time to click the button in the extension, then trigger the action you want to test (submitting a payment, redeeming a voucher, etc.). The extension captures everything: HTTP method, URL, headers, and request body. This data gets sent to the racer.js server you're running, typically on a VPS geographically close to your target.

Here's where the magic happens. The Node.js server receives the captured request and immediately fires off five identical copies using the request library:

for (var i = 0; i < 5; i++) {
  request({
    method: capturedRequest.method,
    url: capturedRequest.url,
    headers: capturedRequest.headers,
    body: capturedRequest.body,
    followRedirect: false
  }, function(error, response, body) {
    console.log('Response ' + i + ':', response.statusCode);
  });
}

The lack of callbacks or promise chaining is intentional—these requests launch asynchronously and race to the target server. Geographic proximity matters enormously here. If you're testing a server in Virginia, running racer.js from a $5 Digital Ocean droplet in the same AWS region means your five requests might arrive within 1-2 milliseconds of each other. That's fast enough to beat most database transaction isolation levels that aren't explicitly using SELECT FOR UPDATE locks.

The tool's simplicity reveals a fundamental truth about race condition vulnerabilities: they're not about sophisticated timing attacks or complex orchestration. They're about developers forgetting that web applications are concurrent systems. When you write if (user.credits > 0) { user.credits -= 1; } without a transaction lock, you've created a vulnerability. Racer exploits this by turning one request into five, increasing the probability that multiple threads read user.credits before any write it back.

What makes Racer particularly effective is that it preserves authentication context perfectly. Cookies, JWT tokens, CSRF tokens—everything gets replayed exactly as your browser sent it. This means you can test authenticated endpoints without manually copying headers or dealing with token refresh logic. The extension sees what the browser sees, and the proxy replays it faithfully.

Gotcha

Racer's greatest strength—its simplicity—is also its primary limitation. The tool sends exactly five parallel requests with no timing control, no conditional logic, and no multi-step orchestration. If you need to test a race condition that requires a specific sequence (like creating a resource with one request while deleting it with another), Racer won't help. It's a single-shot weapon.

The deployment story is also rougher than modern tools. You need to manually sideload the Chrome extension because it's not in the Chrome Web Store, and you need to spin up your own Node.js server. There's no GUI, no request history, and no automated vulnerability detection—you watch the console output and manually verify whether your target application misbehaved. If five redemption requests all returned HTTP 200 instead of four returning errors, you've found a bug. Racer won't tell you that; you need to interpret the results yourself. For systematic testing across multiple endpoints or integration into CI/CD pipelines, you'll want something more robust like Race The Web with its YAML configuration and structured reporting.

Verdict

Use Racer if you're doing security research, bug bounty hunting, or penetration testing and need to quickly check whether common financial operations (payments, credits, vouchers, one-time-use tokens) have race condition vulnerabilities. It's perfect for the 80% case: testing if a developer forgot to add database locks to critical state changes. The one-click workflow means you can test dozens of endpoints in an afternoon without writing custom scripts. Skip it if you need reproducible, automated testing for CI/CD integration, complex multi-request race scenarios, or precise timing control measured in microseconds. Skip it if you're uncomfortable managing your own proxy infrastructure or interpreting raw HTTP responses. For those cases, invest time in Burp Suite's Turbo Intruder or build custom tooling. Racer is the screwdriver in your security toolkit—not sophisticated, but invaluable when you need exactly what it does.

// ADD TO YOUR README
[![Featured on Starlog](https://starlog.is/api/badge/developer-tools/sakurity-racer.svg)](https://starlog.is/api/badge-click/developer-tools/sakurity-racer)