Why Go 1.27 UUIDv7 Generates Predictable “7000” Values in Browsers

In Go 1.27 the standard uuid.NewV7() function produces UUIDs with a constant “7000” segment when compiled to WebAssembly, because browsers deliberately reduce high‑precision timers for Spectre‑style mitigations, causing the 12‑bit random field to collapse to zero and dramatically lowering entropy and collision resistance.

TonyBai
TonyBai
TonyBai
Why Go 1.27 UUIDv7 Generates Predictable “7000” Values in Browsers

UUID v7 implementation in Go 1.27

Go 1.27 adds a native uuid package that implements RFC 9562 UUID v7. The 128‑bit format consists of:

48‑bit unix_ts_ms: millisecond Unix timestamp

4‑bit version field 0111 (hex 7)

12‑bit rand_a: sub‑millisecond fraction or monotonic counter

62‑bit rand_b: cryptographically secure random bits

Observed “7000” pattern in WebAssembly

Running uuid.NewV7() in a browser (GOOS=js GOARCH=wasm) produced UUIDs where the third group is always 7000, e.g.

019ee60f-29b3-7000-a12b-f817e25db8f4
019ee610-29c7-7000-bc34-f04bc09150bb
019ee610-2eb4-7000-884a-dfcad78e47d9

Because the 12‑bit rand_a field collapsed to zero, the version nibble (7) followed by three zero nibbles yields the invariant 7000 segment.

Root cause: timer precision throttling

Modern browsers deliberately round high‑resolution timers ( performance.now(), Date.now()) to mitigate Spectre/Meltdown side‑channel attacks. Rounding granularity is typically 2 ms (Firefox) or up to 100 ms when “Resist Fingerprinting” is enabled.

In a WASM module, Go’s time.Now() obtains the time from the host JavaScript environment. The rounded timestamp provides no sub‑millisecond component, so the value used for rand_a is always zero.

Security impact

On systems with full precision, rand_a contributes 12 bits of entropy, raising the effective random portion of a UUID v7 from 62 bits to 74 bits. In browsers the loss of those 12 bits reduces entropy back to 62 bits, increasing collision probability for high‑throughput, distributed generation (e.g., edge workers or client‑side UUID generation).

Go team fix (CL 792820)

The runtime now detects when the wall‑clock cannot populate rand_a (or when the target platform is GOOS=js) and falls back to crypto/rand to generate the missing 12 bits. The fallback also serves as a monotonic counter when many UUIDs are generated within the same millisecond, preserving ordering.

Implementation steps:

Avoid repeated time.Now() probes that would slow NewV7().

If precision is insufficient, use crypto/rand to fill rand_a.

When multiple UUIDs share a millisecond, treat rand_a as a counter to maintain monotonicity.

Reference

Issue discussion: https://github.com/golang/go/issues/80084

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Gowasmbrowserentropyspectreuuidv7crypto/rand
TonyBai
Written by

TonyBai

Tony Bai's tech world (tonybai.com). Not satisfied with just "knowing how", we strive for mastery. Focused on Go language internals, high-quality engineering practices, and cloud‑native architecture, exploring cutting‑edge intersections of Go and AI. Gophers who pursue technology are welcome—follow me and evolve with Go.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.