← CodeClarityLab Home
Browse by Category
+ added · updated 7d
← Back to glossary

Replay Attack

security CWE-294 OWASP A2:2021 CVSS 7.5 PHP 5.0+ Intermediate
debt(d8/e5/b5/t7)
d8 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'silent in production' (d8), slightly better than d9 because semgrep patterns can flag HMAC-signed requests missing timestamp/nonce fields, but detection_hints says automated:no — missing replay protection produces no errors, tests pass, and attacks leave no obvious trace.

e5 Effort Remediation debt — work required to fix once spotted

Closest to 'touches multiple files / significant refactor in one component' (e5). Quick_fix requires adding nonce+timestamp to signed requests, server-side validation, and Redis-backed nonce storage with TTL — that's a coordinated change across signing, verification, and storage layers, not a one-liner.

b5 Burden Structural debt — long-term weight of choosing wrong

Closest to 'persistent productivity tax' (b5). Once the signed-request protocol exists with nonce/timestamp rules, every new signed endpoint and every webhook integration must conform; applies_to web+api means broad reach across authenticated surfaces.

t7 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'serious trap' (t7). The misconception field is explicit: developers believe HTTPS prevents replay because 'it's encrypted' — this contradicts intuition about TLS protection and is the canonical wrong mental model, making the obvious reasoning ('we use HTTPS, we're safe') wrong.

About DEBT scoring →

Also Known As

credential replay token replay replay attack

TL;DR

An attacker captures a valid request or authentication token and resubmits it later to gain unauthorised access or repeat an action.

Explanation

Replay attacks occur when legitimate authentication messages or transactions are captured and retransmitted. Common examples include replaying captured session cookies, API request signatures without timestamps, or SMS OTP codes before they expire. Defences include: short-lived tokens with nonces, timestamps validated within a narrow window, HMAC signatures that include a timestamp and nonce, and one-time tokens invalidated on first use.

Common Misconception

HTTPS prevents replay attacks because the connection is encrypted. Encryption prevents eavesdropping but not replay — an attacker who captures a valid encrypted request can retransmit it verbatim. Nonces, timestamps, and one-time tokens prevent replay.

Why It Matters

A replay attack reuses a captured valid request — a stolen signed API request can be replayed to repeat the action unless each request includes a timestamp and nonce that the server validates once.

Common Mistakes

  • Not including a timestamp in signed requests — a captured request is valid indefinitely.
  • Not including a nonce — the same request can be submitted multiple times.
  • Long timestamp windows (±1 hour) — captured requests valid for 2 hours.
  • Not storing used nonces to reject duplicates — the nonce check is pointless without server-side tracking.

Code Examples

✗ Vulnerable
// Signed request without timestamp or nonce — replayable:
$signature = hash_hmac('sha256', $payload, $secret);
// Attacker captures payload + signature
// Replays it 1000 times — all accepted

// Replay-protected:
$data = $payload . '|' . time() . '|' . bin2hex(random_bytes(16));
$signature = hash_hmac('sha256', $data, $secret);
// Server: reject if timestamp > 5min old, reject if nonce seen before
✓ Fixed
// Timestamp + nonce — narrow replay window
\$timestamp = time();
\$nonce     = bin2hex(random_bytes(16));
\$payload   = json_encode(['action'=>'transfer','amount'=>100,'ts'=>\$timestamp,'nonce'=>\$nonce]);
\$signature = hash_hmac('sha256', \$payload, \$secret);

// Server verification:
\$ts = \$data['ts'] ?? 0;
if (abs(time() - \$ts) > 300) abort(400);  // reject if older than 5 min

if (\$cache->has('nonce:' . \$data['nonce'])) abort(400);  // already used
\$cache->set('nonce:' . \$data['nonce'], 1, 300);           // mark used

if (!hash_equals(\$signature, \$receivedSig)) abort(401);

Added 15 Mar 2026
Edited 22 Mar 2026
Views 22
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings T 0 pings F 1 ping S 0 pings S 1 ping M 0 pings T 0 pings W 2 pings T 0 pings F 1 ping S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 2 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 1 ping S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F
No pings yet today
No pings yesterday
Amazonbot 7 Perplexity 5 Unknown AI 2 Google 2 ChatGPT 2 Ahrefs 1
crawler 17 crawler_json 2
DEV INTEL Tools & Severity
🟠 High ⚙ Fix effort: Medium
⚡ Quick Fix
Add a nonce or timestamp to signed requests and reject those older than 5 minutes — store used nonces in Redis with TTL to prevent reuse within the window
📦 Applies To
PHP 5.0+ web api
🔗 Prerequisites
🔍 Detection Hints
HMAC-signed requests with no timestamp or nonce; webhook payloads not checked for freshness or replay
Auto-detectable: ✗ No semgrep
⚠ Related Problems
🤖 AI Agent
Confidence: Medium False Positives: Medium ✗ Manual fix Fix: Medium Context: File Tests: Update
CWE-294 CWE-345

✓ schema.org compliant