VYPR
Critical severityNVD Advisory· Published Aug 29, 2018· Updated Aug 5, 2024

CVE-2018-15727

CVE-2018-15727

Description

Grafana 2.x, 3.x, and 4.x before 4.6.4 and 5.x before 5.2.3 allows authentication bypass because an attacker can generate a valid "remember me" cookie knowing only a username of an LDAP or OAuth user.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Grafana 2.x–5.x before 5.2.3 and 4.x before 4.6.4 allows authentication bypass through forged 'remember me' cookies using only a username of an LDAP or OAuth user.

Vulnerability

This authentication bypass vulnerability affects Grafana versions 2.x, 3.x, 4.x before 4.6.4, and 5.x before 5.2.3 [1][2]. The bug resides in the cookie-based "remember me" authentication mechanism. When a user authenticates via LDAP or OAuth, the system generates a "remember me" cookie using a signing key derived from the user's Rands and Password fields. For users created through LDAP or OAuth, these fields could be empty or predictable, allowing an attacker who knows only the username to compute a valid cookie without knowing the actual password [1][4].

Exploitation

An attacker needs only a valid username of an LDAP or OAuth user on the target Grafana instance [1][2]. No authentication or network position beyond standard web access is required. The attacker crafts a "remember me" cookie using the known username—because the signing key (user.Rands + user.Password) may be empty or insufficiently random for these users—and presents it to the server. The server validates the cookie and logs in as that user, bypassing the password check entirely [4]. No user interaction or race condition is needed.

Impact

Successful exploitation grants the attacker full access to the compromised user's account, including any dashboards, data sources, and administrative privileges that user possesses [1]. This constitutes a complete authentication bypass, compromising confidentiality and integrity (reading and modifying dashboards, querying data sources) and potentially availability (if the user has administrative rights). The attack does not require authentication or extended privileges beforehand.

Mitigation

The vulnerability is fixed in Grafana versions 4.6.4 and 5.2.3, released on August 29, 2018 [1]. The fix ensures that Rands and Password fields for LDAP and OAuth users are properly initialized with a random salt and a strong signing key, removing the ability to forge cookies with only a username [4]. Red Hat also released updated packages for Red Hat Gluster Storage 3.4 Web Administration in RHSA-2018:3829 [3]. Users should upgrade to the patched versions immediately; no workaround other than updating is available. The vulnerability is not listed on CISA's Known Exploited Vulnerabilities (KEV) catalog.

AI Insight generated on May 22, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
github.com/grafana/grafanaGo
< 4.6.44.6.4
github.com/grafana/grafanaGo
>= 5.0.0, < 5.2.35.2.3

Affected products

173

Patches

4
1ad5b02166a1

Updated version to 4.6.4.

https://github.com/grafana/grafanaLeonard GramAug 22, 2018via osv
1 file changed · +1 1
  • package.json+1 1 modified
    @@ -4,7 +4,7 @@
         "company": "Grafana Labs"
       },
       "name": "grafana",
    -  "version": "4.6.3",
    +  "version": "4.6.4",
       "repository": {
         "type": "git",
         "url": "http://github.com/grafana/grafana.git"
    
cf4c090fe2e8

Version updated to 5.2.3.

https://github.com/grafana/grafanaLeonard GramAug 22, 2018via osv
1 file changed · +1 1
  • package.json+1 1 modified
    @@ -4,7 +4,7 @@
         "company": "Grafana Labs"
       },
       "name": "grafana",
    -  "version": "5.2.2",
    +  "version": "5.2.3",
       "repository": {
         "type": "git",
         "url": "http://github.com/grafana/grafana.git"
    
7baecf0d0dea

sql: added code migration type

https://github.com/grafana/grafanaLeonard GramAug 22, 2018via ghsa
6 files changed · +89 9
  • pkg/api/login.go+8 1 modified
    @@ -78,7 +78,14 @@ func tryLoginUsingRememberCookie(c *middleware.Context) bool {
     	user := userQuery.Result
     
     	// validate remember me cookie
    -	if val, _ := c.GetSuperSecureCookie(user.Rands+user.Password, setting.CookieRememberName); val != user.Login {
    +	signingKey := user.Rands + user.Password
    +	if len(signingKey) < 10 {
    +		c.Logger.Error("Invalid user signingKey")
    +		return false
    +	}
    +
    +
    +	if val, _ := c.GetSuperSecureCookie(signingKey, setting.CookieRememberName); val != user.Login {
     		return false
     	}
     
    
  • pkg/services/sqlstore/migrations/user_mig.go+39 1 modified
    @@ -1,6 +1,11 @@
     package migrations
     
    -import . "github.com/grafana/grafana/pkg/services/sqlstore/migrator"
    +import (
    +	"fmt"
    +	"github.com/go-xorm/xorm"
    +	. "github.com/grafana/grafana/pkg/services/sqlstore/migrator"
    +	"github.com/grafana/grafana/pkg/util"
    +)
     
     func addUserMigrations(mg *Migrator) {
     	userV1 := Table{
    @@ -107,4 +112,37 @@ func addUserMigrations(mg *Migrator) {
     	mg.AddMigration("Add last_seen_at column to user", NewAddColumnMigration(userV2, &Column{
     		Name: "last_seen_at", Type: DB_DateTime, Nullable: true,
     	}))
    +
    +	// Adds salt & rands for old users who used ldap or oauth
    +	mg.AddMigration("Add missing user data", &AddMissingUserSaltAndRandsMigration{})
    +}
    +
    +type AddMissingUserSaltAndRandsMigration struct {
    +	MigrationBase
    +}
    +
    +func (m *AddMissingUserSaltAndRandsMigration) Sql(dialect Dialect) string {
    +	return "code migration"
    +}
    +
    +type TempUserDTO struct {
    +	Id    int64
    +	Login string
    +}
    +
    +func (m *AddMissingUserSaltAndRandsMigration) Exec(sess *xorm.Session, mg *Migrator) error {
    +	users := make([]*TempUserDTO, 0)
    +
    +	err := sess.Sql(fmt.Sprintf("SELECT id, login from %s WHERE rands = ''", mg.Dialect.Quote("user"))).Find(&users)
    +	if err != nil {
    +		return err
    +	}
    +
    +	for _, user := range users {
    +		_, err := sess.Exec("UPDATE "+mg.Dialect.Quote("user")+" SET salt = ?, rands = ? WHERE id = ?", util.GetRandomString(10), util.GetRandomString(10), user.Id)
    +		if err != nil {
    +			return err
    +		}
    +	}
    +	return nil
     }
    
  • pkg/services/sqlstore/migrator/migrator.go+11 5 modified
    @@ -12,7 +12,7 @@ import (
     
     type Migrator struct {
     	x          *xorm.Engine
    -	dialect    Dialect
    +	Dialect    Dialect
     	migrations []Migration
     	Logger     log.Logger
     }
    @@ -31,7 +31,7 @@ func NewMigrator(engine *xorm.Engine) *Migrator {
     	mg.x = engine
     	mg.Logger = log.New("migrator")
     	mg.migrations = make([]Migration, 0)
    -	mg.dialect = NewDialect(mg.x.DriverName())
    +	mg.Dialect = NewDialect(mg.x.DriverName())
     	return mg
     }
     
    @@ -82,7 +82,7 @@ func (mg *Migrator) Start() error {
     			continue
     		}
     
    -		sql := m.Sql(mg.dialect)
    +		sql := m.Sql(mg.Dialect)
     
     		record := MigrationLog{
     			MigrationId: m.Id(),
    @@ -120,15 +120,21 @@ func (mg *Migrator) exec(m Migration, sess *xorm.Session) error {
     
     	condition := m.GetCondition()
     	if condition != nil {
    -		sql, args := condition.Sql(mg.dialect)
    +		sql, args := condition.Sql(mg.Dialect)
     		results, err := sess.Query(sql, args...)
     		if err != nil || len(results) == 0 {
     			mg.Logger.Info("Skipping migration condition not fulfilled", "id", m.Id())
     			return sess.Rollback()
     		}
     	}
     
    -	_, err := sess.Exec(m.Sql(mg.dialect))
    +	var err error
    +	if codeMigration, ok := m.(CodeMigration); ok {
    +		err = codeMigration.Exec(sess, mg)
    +	} else {
    +		_, err = sess.Exec(m.Sql(mg.Dialect))
    +	}
    +
     	if err != nil {
     		mg.Logger.Error("Executing migration failed", "id", m.Id(), "error", err)
     		return err
    
  • pkg/services/sqlstore/migrator/types.go+6 0 modified
    @@ -2,6 +2,7 @@ package migrator
     
     import (
     	"fmt"
    +	"github.com/go-xorm/xorm"
     	"strings"
     )
     
    @@ -18,6 +19,11 @@ type Migration interface {
     	GetCondition() MigrationCondition
     }
     
    +type CodeMigration interface {
    +	Migration
    +	Exec(sess *xorm.Session, migrator * Migrator) error
    +}
    +
     type SQLType string
     
     type ColumnType string
    
  • pkg/services/sqlstore/user.go+3 2 modified
    @@ -99,9 +99,10 @@ func CreateUser(cmd *m.CreateUserCommand) error {
     			LastSeenAt:    time.Now().AddDate(-10, 0, 0),
     		}
     
    +		user.Salt = util.GetRandomString(10)
    +		user.Rands = util.GetRandomString(10)
    +
     		if len(cmd.Password) > 0 {
    -			user.Salt = util.GetRandomString(10)
    -			user.Rands = util.GetRandomString(10)
     			user.Password = util.EncodePassword(cmd.Password, user.Salt)
     		}
     
    
  • pkg/services/sqlstore/user_test.go+22 0 modified
    @@ -14,6 +14,28 @@ func TestUserDataAccess(t *testing.T) {
     	Convey("Testing DB", t, func() {
     		InitTestDB(t)
     
    +		Convey("Creating a user", func() {
    +			cmd := &models.CreateUserCommand{
    +				Email: "usertest@test.com",
    +				Name:  "user name",
    +				Login: "user_test_login",
    +			}
    +
    +			err := CreateUser(cmd)
    +			So(err, ShouldBeNil)
    +
    +			Convey("Loading a user", func() {
    +				query := models.GetUserByIdQuery{Id: cmd.Result.Id}
    +				err := GetUserById(&query)
    +				So(err, ShouldBeNil)
    +
    +				So(query.Result.Email, ShouldEqual, "usertest@test.com")
    +				So(query.Result.Password, ShouldEqual, "")
    +				So(query.Result.Rands, ShouldHaveLength, 10)
    +				So(query.Result.Salt, ShouldHaveLength, 10)
    +			})
    +		})
    +
     		var err error
     		for i := 0; i < 5; i++ {
     			err = CreateUser(&models.CreateUserCommand{
    
df83bf10a225

sql: added code migration type

https://github.com/grafana/grafanaTorkel ÖdegaardAug 21, 2018via ghsa
6 files changed · +90 9
  • pkg/api/login.go+7 1 modified
    @@ -78,7 +78,13 @@ func tryLoginUsingRememberCookie(c *m.ReqContext) bool {
     	user := userQuery.Result
     
     	// validate remember me cookie
    -	if val, _ := c.GetSuperSecureCookie(user.Rands+user.Password, setting.CookieRememberName); val != user.Login {
    +	signingKey := user.Rands + user.Password
    +	if len(signingKey) < 10 {
    +		c.Logger.Error("Invalid user signingKey")
    +		return false
    +	}
    +
    +	if val, _ := c.GetSuperSecureCookie(signingKey, setting.CookieRememberName); val != user.Login {
     		return false
     	}
     
    
  • pkg/services/sqlstore/migrations/user_mig.go+40 1 modified
    @@ -1,6 +1,12 @@
     package migrations
     
    -import . "github.com/grafana/grafana/pkg/services/sqlstore/migrator"
    +import (
    +	"fmt"
    +
    +	"github.com/go-xorm/xorm"
    +	. "github.com/grafana/grafana/pkg/services/sqlstore/migrator"
    +	"github.com/grafana/grafana/pkg/util"
    +)
     
     func addUserMigrations(mg *Migrator) {
     	userV1 := Table{
    @@ -107,4 +113,37 @@ func addUserMigrations(mg *Migrator) {
     	mg.AddMigration("Add last_seen_at column to user", NewAddColumnMigration(userV2, &Column{
     		Name: "last_seen_at", Type: DB_DateTime, Nullable: true,
     	}))
    +
    +	// Adds salt & rands for old users who used ldap or oauth
    +	mg.AddMigration("Add missing user data", &AddMissingUserSaltAndRandsMigration{})
    +}
    +
    +type AddMissingUserSaltAndRandsMigration struct {
    +	MigrationBase
    +}
    +
    +func (m *AddMissingUserSaltAndRandsMigration) Sql(dialect Dialect) string {
    +	return "code migration"
    +}
    +
    +type TempUserDTO struct {
    +	Id    int64
    +	Login string
    +}
    +
    +func (m *AddMissingUserSaltAndRandsMigration) Exec(sess *xorm.Session, mg *Migrator) error {
    +	users := make([]*TempUserDTO, 0)
    +
    +	err := sess.Sql(fmt.Sprintf("SELECT id, login from %s WHERE rands = ''", mg.Dialect.Quote("user"))).Find(&users)
    +	if err != nil {
    +		return err
    +	}
    +
    +	for _, user := range users {
    +		_, err := sess.Exec("UPDATE "+mg.Dialect.Quote("user")+" SET salt = ?, rands = ? WHERE id = ?", util.GetRandomString(10), util.GetRandomString(10), user.Id)
    +		if err != nil {
    +			return err
    +		}
    +	}
    +	return nil
     }
    
  • pkg/services/sqlstore/migrator/migrator.go+11 5 modified
    @@ -12,7 +12,7 @@ import (
     
     type Migrator struct {
     	x          *xorm.Engine
    -	dialect    Dialect
    +	Dialect    Dialect
     	migrations []Migration
     	Logger     log.Logger
     }
    @@ -31,7 +31,7 @@ func NewMigrator(engine *xorm.Engine) *Migrator {
     	mg.x = engine
     	mg.Logger = log.New("migrator")
     	mg.migrations = make([]Migration, 0)
    -	mg.dialect = NewDialect(mg.x)
    +	mg.Dialect = NewDialect(mg.x)
     	return mg
     }
     
    @@ -86,7 +86,7 @@ func (mg *Migrator) Start() error {
     			continue
     		}
     
    -		sql := m.Sql(mg.dialect)
    +		sql := m.Sql(mg.Dialect)
     
     		record := MigrationLog{
     			MigrationId: m.Id(),
    @@ -122,15 +122,21 @@ func (mg *Migrator) exec(m Migration, sess *xorm.Session) error {
     
     	condition := m.GetCondition()
     	if condition != nil {
    -		sql, args := condition.Sql(mg.dialect)
    +		sql, args := condition.Sql(mg.Dialect)
     		results, err := sess.SQL(sql).Query(args...)
     		if err != nil || len(results) == 0 {
     			mg.Logger.Debug("Skipping migration condition not fulfilled", "id", m.Id())
     			return sess.Rollback()
     		}
     	}
     
    -	_, err := sess.Exec(m.Sql(mg.dialect))
    +	var err error
    +	if codeMigration, ok := m.(CodeMigration); ok {
    +		err = codeMigration.Exec(sess, mg)
    +	} else {
    +		_, err = sess.Exec(m.Sql(mg.Dialect))
    +	}
    +
     	if err != nil {
     		mg.Logger.Error("Executing migration failed", "id", m.Id(), "error", err)
     		return err
    
  • pkg/services/sqlstore/migrator/types.go+7 0 modified
    @@ -3,6 +3,8 @@ package migrator
     import (
     	"fmt"
     	"strings"
    +
    +	"github.com/go-xorm/xorm"
     )
     
     const (
    @@ -19,6 +21,11 @@ type Migration interface {
     	GetCondition() MigrationCondition
     }
     
    +type CodeMigration interface {
    +	Migration
    +	Exec(sess *xorm.Session, migrator *Migrator) error
    +}
    +
     type SQLType string
     
     type ColumnType string
    
  • pkg/services/sqlstore/user.go+3 2 modified
    @@ -104,9 +104,10 @@ func CreateUser(cmd *m.CreateUserCommand) error {
     			LastSeenAt:    time.Now().AddDate(-10, 0, 0),
     		}
     
    +		user.Salt = util.GetRandomString(10)
    +		user.Rands = util.GetRandomString(10)
    +
     		if len(cmd.Password) > 0 {
    -			user.Salt = util.GetRandomString(10)
    -			user.Rands = util.GetRandomString(10)
     			user.Password = util.EncodePassword(cmd.Password, user.Salt)
     		}
     
    
  • pkg/services/sqlstore/user_test.go+22 0 modified
    @@ -14,6 +14,28 @@ func TestUserDataAccess(t *testing.T) {
     	Convey("Testing DB", t, func() {
     		InitTestDB(t)
     
    +		Convey("Creating a user", func() {
    +			cmd := &m.CreateUserCommand{
    +				Email: "usertest@test.com",
    +				Name:  "user name",
    +				Login: "user_test_login",
    +			}
    +
    +			err := CreateUser(context.Background(), cmd)
    +			So(err, ShouldBeNil)
    +
    +			Convey("Loading a user", func() {
    +				query := m.GetUserByIdQuery{Id: cmd.Result.Id}
    +				err := GetUserById(&query)
    +				So(err, ShouldBeNil)
    +
    +				So(query.Result.Email, ShouldEqual, "usertest@test.com")
    +				So(query.Result.Password, ShouldEqual, "")
    +				So(query.Result.Rands, ShouldHaveLength, 10)
    +				So(query.Result.Salt, ShouldHaveLength, 10)
    +			})
    +		})
    +
     		Convey("Given 5 users", func() {
     			var err error
     			var cmd *m.CreateUserCommand
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

10

News mentions

0

No linked articles in our index yet.