GORM Playground Link
https://github.com/go-gorm/playground/pull/661
Description
a UUID that is Nil (= 00000000-0000-0000-0000-000000000000) and being used in a .Where leads to GORM omitting the SQL Where clause, thus leading to wrong / unfiltered results.
In combination with uuid.FromBytesOrNil(), this can be dangerous and leak data in a SELECT or affect to much rows in UPDATE/SET !!
import "github.com/gofrs/uuid"
type MyStruct struct {
UserID uuid.UUID
}
var stuff []MyStruct
user := uuid.FromString("00000000-0000-0000-0000-000000000000") // or simply uuid.Nil
db.Debug().Where(&MyStruct{UserID: user}).Find(&stuff)
// wrong query: SELECT * FROM "my_struct"
but
user := uuid.FromString("10000000-0000-0000-0000-00000000000")
db.Debug().Where(&MyStruct{UserID: user}).Find(&stuff)
// correct query: SELECT * FROM "my_struct" WHERE "my_struct"."user_id" = '10000000-0000-0000-0000-000000000000'
however
user := uuid.FromString("00000000-0000-0000-0000-000000000000")
db.Debug().Where("user_id=?",userID).Find(&stuff)
// results correctly in query: SELECT * FROM "my_struct" WHERE user_id='00000000-0000-0000-0000-000000000000'
https://github.com/go-gorm/gorm/blob/3207ad6033aad5e76c6c9d578ef663032765e484/statement.go#L284 seems to be flawed
Comment From: github-actions[bot]
The issue has been automatically marked as stale as it missing playground pull request link, which is important to help others understand your issue effectively and make sure the issue hasn't been fixed on latest master, checkout https://github.com/go-gorm/playground for details. it will be closed in 30 days if no further activity occurs. if you are asking question, please use the Question template, most likely your question already answered https://github.com/go-gorm/gorm/issues or described in the document https://gorm.io ✨ Search Before Asking ✨
Comment From: ivila
@philicious It's very good for you to provide a reproduction steps, it helps a lot for the investigators. By reading your reproduction steps I think this is not a issue, maybe it's just a misleading or misuse. Your are using a struct for auto filtering.
uuidNull, _ := uuid.FromString("00000000-0000-0000-0000-000000000000") // same as using uuid.Nil or uuid.FromStringOrNil(uuidString)
_ = DB.Debug().Where(&User{UserID: uuidNull}).Find(&resultBad)
but you have to know, the uuidNull is the zero value of the UUID struct
// UUID is an array type to represent the value of a UUID, as defined in RFC-4122.
type UUID [Size]byte
and with a zero value, it just leads to skipping this field. If you want to use the zero value of the UUID for filtering, you may just try any of the following solutions: 1, change this field to a pointer type
type ZeroValueFilterableUser {
UserID *uuid.UUID
}
uuidZero, _ := uuid.FromString("00000000-0000-0000-0000-000000000000")
_ = DB.Debug().Where(ZeroValueFilterableUser {UserID: &uuidZero}).Find(&resultBad)
2,use a map for filtering
uuidZero, _ := uuid.FromString("00000000-0000-0000-0000-000000000000")
_ = DB.Debug().Where(map[string]interface{}{"user_id": uuidZero}).Find(&resultBad)
Comment From: philicious
@ivila thanks for the detailed response. by reading GORM code, I also figured out that zero-values are being omitted.
after reading your answer, I searched and found that its also in the GORM doc https://gorm.io/docs/query.html#Struct-amp-Map-Conditions and therefore not a bug
but I would call this is unfortunate behavior, at least in some scenarios, where your Where clause fields might hold zero-values but are then silently omitted. which can become dangerous.
Its working if you pass in the field as argument and thereby make it a "selectedField"
DB.Debug().Where(&User{UserID: uuidNull}, "UserID").Find(&resultBad)
however thats cumbersome, so I guess its safer and therefore better to not use struct-conditions at all and instead use map-conditions or string-conditions.
..gonna hate an love ORMs and their black magic