IDOR (UUID guessable)
Theory
Why This Matters
The widespread adoption of UUIDs as object identifiers was partly motivated by the belief that their 128-bit space made enumeration attacks impractical compared to sequential integers. However, this belief is only valid for UUID v4 (randomly generated). UUID v1, which encodes the generating host's MAC address, a clock sequence, and a 100-nanosecond timestamp, is predictable once an attacker obtains even a single UUID from the target system. In 2019, researchers demonstrated that UUID v1 IDs generated by popular Node.js and Java libraries could be predicted within a narrow time window, enabling targeted resource enumeration. More commonly, even cryptographically strong UUIDs are rendered insecure by application-level leakage: UUIDs appear in password-reset links, email notifications, API responses for related objects, and access logs — effectively reducing the entropy the attacker must overcome.
Core Concept
UUID (Universally Unique Identifier) is a 128-bit value standardized in RFC 4122 with five versions. The security-relevant distinction is between version 1 and version 4.
UUID v1 structure encodes: a 60-bit timestamp (100-nanosecond intervals since 15 October 1582), a 14-bit clock sequence (to handle clock adjustments), and a 48-bit node field (typically the MAC address of the generating host, or a random value if the MAC is unavailable). Because the timestamp dominates the structure, two UUIDs generated close in time will differ only in their timestamp field. An attacker who obtains one UUID from a target system at a known time can reconstruct the approximate generation timestamp and enumerate nearby UUIDs by varying the timestamp bits within a plausible window.
UUID v1 format (hex groups separated by hyphens): time_low-time_mid-time_hi_and_version-clock_seq-node. The version nibble is 1 in bits 12–15 of the third group.
UUID v4 fills all bits with cryptographically random values (except two version bits). With 122 bits of randomness, brute-force enumeration is computationally infeasible — but only if the UUID is not leaked through other channels.
UUID leakage vectors include: password-reset URLs sent to the target user (if intercepted), webhook confirmation emails, Referer headers when the UUID appears in a URL that the browser follows to an external resource, API responses for related objects (e.g., a shared document response that includes the creator's profile UUID), and server-side logging endpoints left accessible.
Technical Deep-Dive
import uuid, time, struct
# Inspect a UUID v1 and extract its timestamp
sample = uuid.UUID("1ec5d372-4b3a-11ee-be56-0242ac120002")
print(f"Version: {sample.version}") # 1
print(f"Variant: {sample.variant}")
# UUID v1 timestamp = 100-ns intervals since 1582-10-15
UUID_EPOCH_DELTA = 0x01b21dd213814000 # offset to Unix epoch
ts_100ns = sample.time # raw UUID v1 timestamp
unix_ts = (ts_100ns - UUID_EPOCH_DELTA) / 1e7 # convert to Unix seconds
print(f"Generated at: {time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(unix_ts))}")
print(f"Node (MAC or random): {sample.node:#014x}")
# Generate candidate UUIDs within a 1-second window around the known timestamp
# An attacker knows the target account was created at approximately unix_ts
candidates = []
for delta_100ns in range(-10_000_000, 10_000_000, 100): # ±1 second, 100ns steps
new_ts = ts_100ns + delta_100ns
# Reconstruct UUID v1 fields
time_low = new_ts & 0xFFFFFFFF
time_mid = (new_ts >> 32) & 0xFFFF
time_hi = (new_ts >> 48) & 0x0FFF | 0x1000 # version = 1
clock_seq = sample.clock_seq # same clock_seq assumed
node = sample.node
candidate = uuid.UUID(fields=(time_low, time_mid, time_hi, clock_seq >> 8,
clock_seq & 0xFF, node))
candidates.append(str(candidate))
print(f"Generated {len(candidates)} candidates to probe")
# Feed candidates into Burp Intruder or httpx for parallel probing
# Extract all UUIDs from an application's responses using Burp Suite logger
# Grep pattern for UUID v1 detection (version nibble = 1 in third group):
grep -oE '[0-9a-f]{8}-[0-9a-f]{4}-1[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}' burp_log.txt
Security Assessment Methodology
- Collect observed UUIDs — interact with the application, capturing all UUIDs that appear in API responses, URLs, emails, and HTTP headers. Use Burp Suite's Logger++ to extract UUIDs with a regex filter.
- Classify UUID version — inspect the third hyphen-group: a
1in the 13th character indicates v1; a4indicates v4. UUID v1 is the primary target for prediction; UUID v4 targets focus on leakage. - Extract UUID v1 timestamp and node — use the Python
uuidlibrary to decode the sample UUID's generation time and node field. - Generate candidates — write a prediction script (as above) covering a plausible generation window (±60 seconds for account creation, ±5 seconds for short-lived resources).
- Probe candidates at scale — feed the candidate list into Burp Intruder (Sniper mode, payload list) or httpx to test each UUID against the target endpoint. Filter 200 responses.
- For UUID v4, hunt for leakage — check password-reset flows, invitation links, email footers, and
Refererheaders for UUID exposure. If a UUID leaks, use it directly without prediction. - Verify with two-account testing — confirm that a leaked or predicted UUID belonging to Account B is accessible when authenticated as Account A.
Defensive Countermeasure — Use UUID v4 (or ULID with cryptographic randomness) exclusively for all externally exposed object identifiers. Audit all application flows that transmit UUIDs to confirm they do not appear in Referer headers, email bodies accessible to third parties, or unauthenticated API responses. Log access attempts and alert on unusual enumeration patterns (high volume of 404s from a single IP against UUID-shaped paths).
Common Assessment Errors
- Assuming all UUIDs are equally random — the version digit distinguishes predictable v1 from random v4; always decode a sample before concluding that UUIDs are safe.
- Missing UUID leakage in email flows — password-reset and invitation emails that include a UUID in the URL are the most common source of targeted UUID theft; test these flows explicitly.
- Generating too narrow a prediction window — server clock drift, load-balancer forwarding delays, and queued processing can shift the actual UUID generation time by several seconds from the observed request time; use at least ±60 seconds.
- Not checking the node field — if the node field is not the MAC address but a random value, it resets on process restart, meaning UUIDs generated in different server instances have different node values and candidate sets must account for this.
- Ignoring Referer header leakage — a page at
https://victim.com/docs/<uuid>that loads a third-party script will send the UUID in theRefererheader to the third-party origin; check JS bundle analytics, fonts, and CDN references. - Treating UUID v4 as unhackable — 122 bits of randomness is infeasible to brute-force, but a UUID that appears in only one additional place (a 404 error page, a debug header) is no longer secret.
NICE Framework Alignment
| Code | Knowledge/Skill/Task Statement | How This Card Develops It |
|---|---|---|
| K0007 | Knowledge of authentication, authorization, and access control methods | Covers identifier-based access control and why UUID version and leakage behaviour determine real-world exploitability |
| K0065 | Knowledge of policy-based and attribute-based access control | Reinforces that cryptographic identifier strength is a component of access policy, not a substitute for server-side ownership checks |
| S0001 | Skill in conducting vulnerability scans and recognizing vulnerabilities in security systems | Practises UUID version classification, timestamp extraction, candidate generation, and Burp-based probing |
| T0028 | Task: Identify systemic security issues based on vulnerability and configuration data | Develops the ability to recognise UUID v1 as a systemic identifier weakness and leakage as a design-level exposure |
Further Reading
- RFC 4122: A Universally Unique IDentifier (UUID) URN Namespace — IETF (Leach, Mealling, Salz)
- OWASP API Security Top 10 — API1:2023 Broken Object Level Authorization — OWASP Foundation
- UUID1 Vulnerability in Production Systems — Dan Kaminsky, blog post
- Hacking APIs: Breaking Web Application Programming Interfaces — Corey Ball, No Starch Press (2022)
Challenge Lab
Reinforce your learning with a hands-on generated challenge based on this card's competency.