New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NewV4: non-random uuid #73

josselin-c opened this Issue Mar 23, 2018 · 24 comments


None yet

josselin-c commented Mar 23, 2018

I'm running this on my macbook pro.

I'm using uuid.Must(uuid.NewV4()).String() to generate random identifiers. I'm generating theses identifiers at a very low rate of a few dozen per days

Here are some non-random UUID that I got in the last weeks:


I think I shouldn't have theses.


This comment has been minimized.

domino14 commented Apr 3, 2018

humans are bad at telling randomness. While it is extraordinarily, astronomically unlikely that you would have so many uuids with that many zeros, it is still theoretically possible.


This comment has been minimized.

josselin-c commented Apr 3, 2018

In an IDs such as 80730000-0000-4000-8000-000000000000 there are ~14 consecutive bytes of zeros.. While a probability of something like 1/2**(14*8) isn't nil, it's still too low for my taste. Drawing theses IDs 5 times out of ~1000 isn't just bad luck. In real life, if it was possible, I would start mining bitcoins with my super powers!


I don't know the root cause of this.


This comment has been minimized.

peterstace commented Apr 3, 2018

These UUIDs seem suspiciously non-random to me as well.

NewV4 gets its randomness from crypto/rand.Reader (and is basically a passthrough to populate a UUID). The code in NewV4 is really simple, I don't see how it could go wrong.

The only possibilities I can think of:

  • There is a bug in crypto/rand (seems unlikely).
  • Since crypto/rand.Reader is just a variable, some malicious/accidental code could be swapping it out for a less random io.Reader implementation.

This comment has been minimized.

josselin-c commented Apr 4, 2018

Okay, I can reproduce it!
On my machine I have two separate processes: one webserver (ServerA) that calls uuid.Must(uuid.NewV4()).String() while simultaneously doing http requests to another webserver (ServerB) used for image resizing (imgproxy).

I instrumented ServerA with this code:

	go func() {
		for {
			time.Sleep(1 * time.Second)
			for i := 0; i < 1000; i++ {
				u := uuid.Must(uuid.NewV4()).String()
				if strings.Contains(u, "000000000") {

Which runs without crashing if ServerA idle or handling standard requests. If ServerA is calling ServerB (to resize images), the ServerA immediately crash with a bad uuid.
I'll try to make a self-contained reproducer


This comment has been minimized.

josselin-c commented Apr 4, 2018

Okay, I found the problem.
Here is the current NewV4 code:

// NewV4 returns random generated UUID.
func (g *rfc4122Generator) NewV4() (UUID, error) {
	var err error
	var c int
	u := UUID{}
	if _, err = g.rand.Read(u[:]); err != nil {
		return Nil, err

	return u, nil

Read() gives no guaranties about the number of bytes actually read. From

Read reads up to len(p) bytes into p. It returns the number of bytes read (0 <= n <= len(p)) and any error encountered

Turns out, on some occasions Read would read less than len(u) bytes. I thinks uuid should use ReadFull instead of plain Read().


This comment has been minimized.

domino14 commented Apr 4, 2018

@josselin-c Could you make a patch and see if you can reproduce the error with your script and ReadFull? I wonder if using ReadFull would outright return an error in this case, because there aren't enough bytes to read.


This comment has been minimized.

domino14 commented Apr 4, 2018

One more thing that is interesting to me is the fact that the UUIDs you posted are not of equal length.

josselin-c pushed a commit to josselin-c/go.uuid that referenced this issue Apr 4, 2018

Josselin Costanzi
Fix potential non-random UUIDs
Use ReadFull to fetch random bytes from crypto/rand instead of calling
Read directly as Read may read less bytes than asked.

Fix satori#73

This comment has been minimized.

mikesun commented Jun 1, 2018

So it looks like this commit introduced the bug: 0ef6afb

Prior to that commit, rand.Read() was used, which is a wrapper that uses io.ReadFull():


This comment has been minimized.

CameronAckermanSEL commented Jul 10, 2018

How is a critical bug like this still unresolved? Especially given that someone already did the work to fix it.


This comment has been minimized.

theckman commented Jul 18, 2018

A few people in the Go community have banded together to adopt this package. We've just cut a v2.0.0 release of our fork:

This is a GitHub organization with a few community members in it, so this package isn't being maintained by one individual. We're also available on the Gophers slack in #gofrs.


This comment has been minimized.

rkuris commented Jul 18, 2018


This comment has been minimized.

zerkms commented Jul 18, 2018

@rkuris gofrs being an activists collaboration is open for any suggestions, as soon as we all can agree it adds value to the project

A required note: this is not an official position, just my personal understanding of the aim of the organisation.


This comment has been minimized.

sethgrid commented Aug 16, 2018

@josselin-c could you update the issue description and link to the new project?

arkhaix added a commit to arkhaix/go-epub that referenced this issue Aug 24, 2018

Switched to google/uuid
satori/uuid can sometimes fail to retrieve enough random bytes from the random stream, and the maintainers aren't fixing it.  See satori/go.uuid#73

talal added a commit to sapcc/limes that referenced this issue Sep 18, 2018

majewsky added a commit to sapcc/limes that referenced this issue Sep 26, 2018

talal added a commit to sapcc/limes that referenced this issue Sep 26, 2018

@satori satori closed this in #75 Oct 16, 2018

@ceriath ceriath referenced this issue Nov 13, 2018


Remove go.uuid #2224

avelino added a commit to avelino/awesome-go that referenced this issue Nov 14, 2018

Remove go.uuid (#2224)
go.uuid is currently the most starred uuid repo for go. However, it is unmaintained and contains at least one critical security, which has been fixed by PR but took nearly half a year to be merged, since the owner is not really active (satori/go.uuid#75). There is an actively maintained fork at which is already listed here too. go.uuid should be removed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment