VYPR
Moderate severityNVD Advisory· Published Jun 19, 2020· Updated Aug 5, 2024

CVE-2017-18878

CVE-2017-18878

Description

An issue was discovered in Mattermost Server before 4.3.0, 4.2.1, and 4.1.2. Knowledge of a session ID allows revoking another user's session.

AI Insight

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

Mattermost Server before 4.3.0/4.2.1/4.1.2 allows any user to revoke another user's session if the session ID is known, due to insufficient authorization checks.

Vulnerability

Description

Mattermost Server versions prior to 4.3.0, 4.2.1, and 4.1.2 contain an authorization vulnerability in the session revocation endpoint. The flaw occurs because the server does not verify that the session being revoked belongs to the authenticated user making the request. As a result, an attacker who obtains a valid session ID can revoke that session, effectively logging out the victim [1].

Exploitation

Conditions

Exploitation requires knowledge of a target user's session ID. While session IDs are typically not disclosed, they could be obtained through other means such as cross-site scripting, network sniffing, or access to server logs. No special privileges are needed beyond a valid user account to make the revocation request. The attack can be performed over the network without authentication for the CVSS scoring, but practical exploitation often requires some initial access or information leakage.

Impact

A successful attack forces a user's session to be terminated, causing denial of service for that user. Repeated session revocation could prevent normal use of Mattermost. The vulnerability does not allow data theft or privilege escalation, but it disrupts availability and may facilitate further attacks if combined with other weaknesses.

Mitigation

The issue is fixed in Mattermost Server versions 4.3.0, 4.2.1, and 4.1.2. The fix ensures that the session ID submitted for revocation belongs to the current user, preventing unauthorized revocation [4]. Administrators should update to these or later versions. No known workarounds exist; upgrading is the recommended remediation.

AI Insight generated on May 21, 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/mattermost/mattermost-serverGo
< 4.1.2-0.20171004201910-6be8113eb60c4.1.2-0.20171004201910-6be8113eb60c
github.com/mattermost/mattermost-serverGo
>= 4.2.0-rc1, < 4.2.1-0.20171004192657-8fbbd688ea244.2.1-0.20171004192657-8fbbd688ea24
github.com/mattermost/mattermost-serverGo
>= 4.3.0-rc1, < 4.3.04.3.0

Affected products

3

Patches

3
6be8113eb60c

Various patches

https://github.com/mattermost/mattermostJoramWilanderOct 4, 2017via ghsa
14 files changed · +229 60
  • api4/channel_test.go+1 1 modified
    @@ -1473,7 +1473,7 @@ func TestGetChannelUnread(t *testing.T) {
     	CheckNoError(t, resp)
     
     	_, resp = th.SystemAdminClient.GetChannelUnread(model.NewId(), user.Id)
    -	CheckNotFoundStatus(t, resp)
    +	CheckForbiddenStatus(t, resp)
     
     	_, resp = th.SystemAdminClient.GetChannelUnread(channel.Id, model.NewId())
     	CheckNotFoundStatus(t, resp)
    
  • api4/command_test.go+3 6 modified
    @@ -470,30 +470,27 @@ func TestExecuteCommand(t *testing.T) {
     
     func TestExecuteCommandAgainstChannelOnAnotherTeam(t *testing.T) {
     	th := Setup().InitBasic().InitSystemAdmin()
    -	defer th.TearDown()
    +	defer TearDown()
     	Client := th.Client
     	channel := th.BasicChannel
     
     	enableCommands := *utils.Cfg.ServiceSettings.EnableCommands
    -	allowedInternalConnections := *utils.Cfg.ServiceSettings.AllowedUntrustedInternalConnections
     	defer func() {
     		utils.Cfg.ServiceSettings.EnableCommands = &enableCommands
    -		utils.Cfg.ServiceSettings.AllowedUntrustedInternalConnections = &allowedInternalConnections
     	}()
     	*utils.Cfg.ServiceSettings.EnableCommands = true
    -	*utils.Cfg.ServiceSettings.AllowedUntrustedInternalConnections = "localhost"
     
     	// create a slash command on some other team where we have permission to do so
     	team2 := th.CreateTeam()
     	postCmd := &model.Command{
     		CreatorId: th.BasicUser.Id,
     		TeamId:    team2.Id,
    -		URL:       "http://localhost" + *utils.Cfg.ServiceSettings.ListenAddress + model.API_URL_SUFFIX_V4 + "/teams/command_test",
    +		URL:       "http://localhost" + utils.Cfg.ServiceSettings.ListenAddress + model.API_URL_SUFFIX_V4 + "/teams/command_test",
     		Method:    model.COMMAND_METHOD_POST,
     		Trigger:   "postcommand",
     	}
     
    -	if _, err := th.App.CreateCommand(postCmd); err != nil {
    +	if _, err := app.CreateCommand(postCmd); err != nil {
     		t.Fatal("failed to create post command")
     	}
     
    
  • api4/file_test.go+9 0 modified
    @@ -100,6 +100,15 @@ func TestUploadFile(t *testing.T) {
     	_, resp := Client.UploadFile(data, model.NewId(), "test.png")
     	CheckForbiddenStatus(t, resp)
     
    +	_, resp = Client.UploadFile(data, "../../junk", "test.png")
    +	CheckForbiddenStatus(t, resp)
    +
    +	_, resp = th.SystemAdminClient.UploadFile(data, model.NewId(), "test.png")
    +	CheckForbiddenStatus(t, resp)
    +
    +	_, resp = th.SystemAdminClient.UploadFile(data, "../../junk", "test.png")
    +	CheckForbiddenStatus(t, resp)
    +
     	_, resp = th.SystemAdminClient.UploadFile(data, channel.Id, "test.png")
     	CheckNoError(t, resp)
     
    
  • api4/user.go+59 1 modified
    @@ -539,6 +539,20 @@ func updateUser(c *Context, w http.ResponseWriter, r *http.Request) {
     		return
     	}
     
    +	if c.Session.IsOAuth {
    +		ouser, err := app.GetUser(user.Id)
    +		if err != nil {
    +			c.Err = err
    +			return
    +		}
    +
    +		if ouser.Email != user.Email {
    +			c.SetPermissionError(model.PERMISSION_EDIT_OTHER_USERS)
    +			c.Err.DetailedError += ", attempted email update by oauth app"
    +			return
    +		}
    +	}
    +
     	if ruser, err := app.UpdateUserAsUser(user, c.IsSystemAdmin()); err != nil {
     		c.Err = err
     		return
    @@ -565,6 +579,20 @@ func patchUser(c *Context, w http.ResponseWriter, r *http.Request) {
     		return
     	}
     
    +	if c.Session.IsOAuth && patch.Email != nil {
    +		ouser, err := app.GetUser(c.Params.UserId)
    +		if err != nil {
    +			c.Err = err
    +			return
    +		}
    +
    +		if ouser.Email != *patch.Email {
    +			c.SetPermissionError(model.PERMISSION_EDIT_OTHER_USERS)
    +			c.Err.DetailedError += ", attempted email update by oauth app"
    +			return
    +		}
    +	}
    +
     	if ruser, err := app.PatchUser(c.Params.UserId, patch, c.IsSystemAdmin()); err != nil {
     		c.Err = err
     		return
    @@ -693,6 +721,12 @@ func updateUserMfa(c *Context, w http.ResponseWriter, r *http.Request) {
     		return
     	}
     
    +	if c.Session.IsOAuth {
    +		c.SetPermissionError(model.PERMISSION_EDIT_OTHER_USERS)
    +		c.Err.DetailedError += ", attempted access by oauth app"
    +		return
    +	}
    +
     	if !app.SessionHasPermissionToUser(c.Session, c.Params.UserId) {
     		c.SetPermissionError(model.PERMISSION_EDIT_OTHER_USERS)
     		return
    @@ -732,6 +766,12 @@ func generateMfaSecret(c *Context, w http.ResponseWriter, r *http.Request) {
     		return
     	}
     
    +	if c.Session.IsOAuth {
    +		c.SetPermissionError(model.PERMISSION_EDIT_OTHER_USERS)
    +		c.Err.DetailedError += ", attempted access by oauth app"
    +		return
    +	}
    +
     	if !app.SessionHasPermissionToUser(c.Session, c.Params.UserId) {
     		c.SetPermissionError(model.PERMISSION_EDIT_OTHER_USERS)
     		return
    @@ -928,7 +968,19 @@ func revokeSession(c *Context, w http.ResponseWriter, r *http.Request) {
     		c.SetInvalidParam("session_id")
     	}
     
    -	if err := app.RevokeSessionById(sessionId); err != nil {
    +	var session *model.Session
    +	var err *model.AppError
    +	if session, err = app.GetSessionById(sessionId); err != nil {
    +		c.Err = err
    +		return
    +	}
    +
    +	if session.UserId != c.Params.UserId {
    +		c.SetInvalidUrlParam("user_id")
    +		return
    +	}
    +
    +	if err := app.RevokeSession(session); err != nil {
     		c.Err = err
     		return
     	}
    @@ -1093,6 +1145,12 @@ func createUserAccessToken(c *Context, w http.ResponseWriter, r *http.Request) {
     		return
     	}
     
    +	if c.Session.IsOAuth {
    +		c.SetPermissionError(model.PERMISSION_CREATE_USER_ACCESS_TOKEN)
    +		c.Err.DetailedError += ", attempted access by oauth app"
    +		return
    +	}
    +
     	accessToken := model.UserAccessTokenFromJson(r.Body)
     	if accessToken == nil {
     		c.SetInvalidParam("user_access_token")
    
  • api4/user_test.go+89 28 modified
    @@ -994,6 +994,15 @@ func TestUpdateUser(t *testing.T) {
     		}
     	}
     
    +	session, _ := app.GetSession(Client.AuthToken)
    +	session.IsOAuth = true
    +	app.AddSessionToCache(session)
    +
    +	ruser.Id = user.Id
    +	ruser.Email = GenerateTestEmail()
    +	_, resp = Client.UpdateUser(ruser)
    +	CheckForbiddenStatus(t, resp)
    +
     	Client.Logout()
     	_, resp = Client.UpdateUser(user)
     	CheckUnauthorizedStatus(t, resp)
    @@ -1073,6 +1082,15 @@ func TestPatchUser(t *testing.T) {
     		}
     	}
     
    +	session, _ := app.GetSession(Client.AuthToken)
    +	session.IsOAuth = true
    +	app.AddSessionToCache(session)
    +
    +	patch.Email = new(string)
    +	*patch.Email = GenerateTestEmail()
    +	_, resp = Client.PatchUser(user.Id, patch)
    +	CheckForbiddenStatus(t, resp)
    +
     	Client.Logout()
     	_, resp = Client.PatchUser(user.Id, patch)
     	CheckUnauthorizedStatus(t, resp)
    @@ -1508,7 +1526,7 @@ func TestGetUsersNotInChannel(t *testing.T) {
     	CheckNoError(t, resp)
     }
     
    -/*func TestUpdateUserMfa(t *testing.T) {
    +func TestUpdateUserMfa(t *testing.T) {
     	th := Setup().InitBasic().InitSystemAdmin()
     	defer TearDown()
     	Client := th.Client
    @@ -1518,37 +1536,42 @@ func TestGetUsersNotInChannel(t *testing.T) {
     	enableMfa := *utils.Cfg.ServiceSettings.EnableMultifactorAuthentication
     	defer func() {
     		utils.IsLicensed = isLicensed
    -		utils.License = license
    +		utils.SetLicense(license)
     		*utils.Cfg.ServiceSettings.EnableMultifactorAuthentication = enableMfa
     	}()
     	utils.IsLicensed = true
    -	utils.License = &model.License{Features: &model.Features{}}
    +	utils.SetLicense(&model.License{Features: &model.Features{}})
     	utils.License.Features.SetDefaults()
    +	*utils.License.Features.MFA = true
    +	*utils.Cfg.ServiceSettings.EnableMultifactorAuthentication = true
     
    -	team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
    -	rteam, _ := Client.CreateTeam(&team)
    -
    -	user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
    -	ruser, _ := Client.CreateUser(&user)
    -	LinkUserToTeam(ruser, rteam)
    -	store.Must(app.Srv.Store.User().VerifyEmail(ruser.Id))
    -
    -	Client.Logout()
    -	_, resp := Client.UpdateUserMfa(ruser.Id, "12334", true)
    -	CheckUnauthorizedStatus(t, resp)
    -
    -	Client.Login(user.Email, user.Password)
    -	_, resp = Client.UpdateUserMfa("fail", "56789", false)
    -	CheckBadRequestStatus(t, resp)
    -
    -	_, resp = Client.UpdateUserMfa(ruser.Id, "", true)
    -	CheckErrorMessage(t, resp, "api.context.invalid_body_param.app_error")
    +	session, _ := app.GetSession(Client.AuthToken)
    +	session.IsOAuth = true
    +	app.AddSessionToCache(session)
     
    -	*utils.Cfg.ServiceSettings.EnableMultifactorAuthentication = true
    +	_, resp := Client.UpdateUserMfa(th.BasicUser.Id, "12345", false)
    +	CheckForbiddenStatus(t, resp)
     
    -	_, resp = Client.UpdateUserMfa(ruser.Id, "123456", false)
    -	CheckNotImplementedStatus(t, resp)
    -}*/
    +	/*
    +		team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
    +		rteam, _ := Client.CreateTeam(&team)
    +		user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "passwd1"}
    +		ruser, _ := Client.CreateUser(&user)
    +		th.LinkUserToTeam(ruser, rteam)
    +		store.Must(app.Srv.Store.User().VerifyEmail(ruser.Id))
    +		Client.Logout()
    +		_, resp := Client.UpdateUserMfa(ruser.Id, "12334", true)
    +		CheckUnauthorizedStatus(t, resp)
    +		Client.Login(user.Email, user.Password)
    +		_, resp = Client.UpdateUserMfa("fail", "56789", false)
    +		CheckBadRequestStatus(t, resp)
    +		_, resp = Client.UpdateUserMfa(ruser.Id, "", true)
    +		CheckErrorMessage(t, resp, "api.context.invalid_body_param.app_error")
    +		*utils.Cfg.ServiceSettings.EnableMultifactorAuthentication = true
    +		_, resp = Client.UpdateUserMfa(ruser.Id, "123456", false)
    +		CheckNotImplementedStatus(t, resp)
    +	*/
    +}
     
     func TestCheckUserMfa(t *testing.T) {
     	th := Setup().InitBasic().InitSystemAdmin()
    @@ -1615,19 +1638,40 @@ func TestGenerateMfaSecret(t *testing.T) {
     	_, resp := Client.GenerateMfaSecret(th.BasicUser.Id)
     	CheckNotImplementedStatus(t, resp)
     
    +	_, resp = th.SystemAdminClient.GenerateMfaSecret(th.BasicUser.Id)
    +	CheckNotImplementedStatus(t, resp)
    +
     	_, resp = Client.GenerateMfaSecret("junk")
     	CheckBadRequestStatus(t, resp)
     
    +	isLicensed := utils.IsLicensed
    +	license := utils.License
    +	enableMfa := *utils.Cfg.ServiceSettings.EnableMultifactorAuthentication
    +	defer func() {
    +		utils.IsLicensed = isLicensed
    +		utils.SetLicense(license)
    +		*utils.Cfg.ServiceSettings.EnableMultifactorAuthentication = enableMfa
    +	}()
    +	utils.IsLicensed = true
    +	utils.SetLicense(&model.License{Features: &model.Features{}})
    +	utils.License.Features.SetDefaults()
    +	*utils.License.Features.MFA = true
    +	*utils.Cfg.ServiceSettings.EnableMultifactorAuthentication = true
    +
     	_, resp = Client.GenerateMfaSecret(model.NewId())
     	CheckForbiddenStatus(t, resp)
     
    +	session, _ := app.GetSession(Client.AuthToken)
    +	session.IsOAuth = true
    +	app.AddSessionToCache(session)
    +
    +	_, resp = Client.GenerateMfaSecret(th.BasicUser.Id)
    +	CheckForbiddenStatus(t, resp)
    +
     	Client.Logout()
     
     	_, resp = Client.GenerateMfaSecret(th.BasicUser.Id)
     	CheckUnauthorizedStatus(t, resp)
    -
    -	_, resp = th.SystemAdminClient.GenerateMfaSecret(th.BasicUser.Id)
    -	CheckNotImplementedStatus(t, resp)
     }
     
     func TestUpdateUserPassword(t *testing.T) {
    @@ -1880,6 +1924,14 @@ func TestRevokeSessions(t *testing.T) {
     	}
     	CheckNoError(t, resp)
     
    +	th.LoginBasic()
    +
    +	sessions, _ = app.GetSessions(th.SystemAdminUser.Id)
    +	session = sessions[0]
    +
    +	_, resp = Client.RevokeSession(user.Id, session.Id)
    +	CheckBadRequestStatus(t, resp)
    +
     	Client.Logout()
     	_, resp = Client.RevokeSession(user.Id, model.NewId())
     	CheckUnauthorizedStatus(t, resp)
    @@ -2212,6 +2264,15 @@ func TestCreateUserAccessToken(t *testing.T) {
     	if ruser.Id != th.BasicUser.Id {
     		t.Fatal("returned wrong user")
     	}
    +
    +	Client.AuthToken = oldSessionToken
    +
    +	session, _ := app.GetSession(Client.AuthToken)
    +	session.IsOAuth = true
    +	app.AddSessionToCache(session)
    +
    +	_, resp = Client.CreateUserAccessToken(th.BasicUser.Id, testDescription)
    +	CheckForbiddenStatus(t, resp)
     }
     
     func TestGetUserAccessToken(t *testing.T) {
    
  • api4/webhook_test.go+1 5 modified
    @@ -387,11 +387,7 @@ func TestGetOutgoingWebhooks(t *testing.T) {
     	}
     
     	hooks, resp = th.SystemAdminClient.GetOutgoingWebhooksForChannel(model.NewId(), 0, 1000, "")
    -	CheckNoError(t, resp)
    -
    -	if len(hooks) != 0 {
    -		t.Fatal("no hooks should be returned")
    -	}
    +	CheckForbiddenStatus(t, resp)
     
     	_, resp = Client.GetOutgoingWebhooks(0, 1000, "")
     	CheckForbiddenStatus(t, resp)
    
  • api/file_test.go+20 2 modified
    @@ -24,7 +24,7 @@ import (
     )
     
     func TestUploadFile(t *testing.T) {
    -	th := Setup().InitBasic()
    +	th := Setup().InitBasic().InitSystemAdmin()
     
     	if utils.Cfg.FileSettings.DriverName == "" {
     		t.Logf("skipping because no file driver is enabled")
    @@ -37,7 +37,9 @@ func TestUploadFile(t *testing.T) {
     	channel := th.BasicChannel
     
     	var uploadInfo *model.FileInfo
    -	if data, err := readTestFile("test.png"); err != nil {
    +	var data []byte
    +	var err error
    +	if data, err = readTestFile("test.png"); err != nil {
     		t.Fatal(err)
     	} else if resp, err := Client.UploadPostAttachment(data, channel.Id, "test.png"); err != nil {
     		t.Fatal(err)
    @@ -100,6 +102,22 @@ func TestUploadFile(t *testing.T) {
     		t.Fatalf("file preview should've been saved in %v", expectedPreviewPath)
     	}
     
    +	if _, err := Client.UploadPostAttachment(data, model.NewId(), "test.png"); err == nil || err.StatusCode != http.StatusForbidden {
    +		t.Fatal("should have failed - bad channel id")
    +	}
    +
    +	if _, err := Client.UploadPostAttachment(data, "../../junk", "test.png"); err == nil || err.StatusCode != http.StatusForbidden {
    +		t.Fatal("should have failed - bad channel id")
    +	}
    +
    +	if _, err := th.SystemAdminClient.UploadPostAttachment(data, model.NewId(), "test.png"); err == nil || err.StatusCode != http.StatusForbidden {
    +		t.Fatal("should have failed - bad channel id")
    +	}
    +
    +	if _, err := th.SystemAdminClient.UploadPostAttachment(data, "../../junk", "test.png"); err == nil || err.StatusCode != http.StatusForbidden {
    +		t.Fatal("should have failed - bad channel id")
    +	}
    +
     	enableFileAttachments := *utils.Cfg.FileSettings.EnableFileAttachments
     	defer func() {
     		*utils.Cfg.FileSettings.EnableFileAttachments = enableFileAttachments
    
  • api/oauth_test.go+0 8 modified
    @@ -719,14 +719,6 @@ func TestOAuthAccessToken(t *testing.T) {
     		t.Fatal("Should have failed - code is expired")
     	}
     
    -	authData = &model.AuthData{ClientId: oauthApp.Id, RedirectUri: oauthApp.CallbackUrls[0], UserId: th.BasicUser.Id, Code: model.NewId(), ExpiresIn: model.AUTHCODE_EXPIRE_TIME}
    -	<-app.Srv.Store.OAuth().SaveAuthData(authData)
    -
    -	data.Set("code", authData.Code)
    -	if _, err := Client.GetAccessToken(data); err == nil {
    -		t.Fatal("Should have failed - code with invalid hash comparission")
    -	}
    -
     	Client.ClearOAuthToken()
     }
     
    
  • app/authorization.go+3 0 modified
    @@ -4,6 +4,7 @@
     package app
     
     import (
    +	"net/http"
     	"strings"
     
     	l4g "github.com/alecthomas/log4go"
    @@ -50,6 +51,8 @@ func SessionHasPermissionToChannel(session model.Session, channelId string, perm
     	channel, err := GetChannel(channelId)
     	if err == nil && channel.TeamId != "" {
     		return SessionHasPermissionToTeam(session, channel.TeamId, permission)
    +	} else if err != nil && err.StatusCode == http.StatusNotFound {
    +		return false
     	}
     
     	return SessionHasPermissionTo(session, permission)
    
  • app/file.go+4 1 modified
    @@ -462,8 +462,11 @@ func UploadFiles(teamId string, channelId string, userId string, fileHeaders []*
     	return resStruct, nil
     }
     
    -func DoUploadFile(teamId string, channelId string, userId string, rawFilename string, data []byte) (*model.FileInfo, *model.AppError) {
    +func DoUploadFile(rawTeamId string, rawChannelId string, rawUserId string, rawFilename string, data []byte) (*model.FileInfo, *model.AppError) {
     	filename := filepath.Base(rawFilename)
    +	teamId := filepath.Base(rawTeamId)
    +	channelId := filepath.Base(rawChannelId)
    +	userId := filepath.Base(rawUserId)
     
     	info, err := model.GetInfoForBytes(filename, data)
     	if err != nil {
    
  • app/file_test.go+17 0 modified
    @@ -4,9 +4,12 @@
     package app
     
     import (
    +	"fmt"
     	"testing"
    +	"time"
     
     	"github.com/mattermost/platform/model"
    +	"github.com/mattermost/platform1/platform/utils"
     )
     
     func TestGeneratePublicLinkHash(t *testing.T) {
    @@ -30,4 +33,18 @@ func TestGeneratePublicLinkHash(t *testing.T) {
     	if hash1 == hash3 {
     		t.Fatal("hashes for the same file with different salts should not be equal")
     	}
    +
    +	info4, err := DoUploadFile(time.Date(2009, 3, 5, 1, 2, 3, 4, time.Local), "../../"+teamId, "../../"+channelId, "../../"+userId, "../../"+filename, data)
    +	if err != nil {
    +		t.Fatal(err)
    +	} else {
    +		defer func() {
    +			<-Srv.Store.FileInfo().PermanentDelete(info3.Id)
    +			utils.RemoveFile(info3.Path)
    +		}()
    +	}
    +
    +	if info4.Path != fmt.Sprintf("20090305/teams/%v/channels/%v/users/%v/%v/%v", teamId, channelId, userId, info4.Id, filename) {
    +		t.Fatal("stored file at incorrect path", info4.Path)
    +	}
     }
    
  • app/oauth.go+1 6 modified
    @@ -6,7 +6,6 @@ package app
     import (
     	"bytes"
     	b64 "encoding/base64"
    -	"fmt"
     	"io"
     	"io/ioutil"
     	"net/http"
    @@ -116,7 +115,7 @@ func AllowOAuthAppAccessToUser(userId string, authRequest *model.AuthorizeReques
     	}
     
     	authData := &model.AuthData{UserId: userId, ClientId: authRequest.ClientId, CreateAt: model.GetMillis(), RedirectUri: authRequest.RedirectUri, State: authRequest.State, Scope: authRequest.Scope}
    -	authData.Code = utils.HashSha256(fmt.Sprintf("%v:%v:%v:%v", authRequest.ClientId, authRequest.RedirectUri, authData.CreateAt, userId))
    +	authData.Code = model.NewId() + model.NewId()
     
     	// this saves the OAuth2 app as authorized
     	authorizedApp := model.Preference{
    @@ -174,10 +173,6 @@ func GetOAuthAccessToken(clientId, grantType, redirectUri, code, secret, refresh
     			return nil, model.NewAppError("GetOAuthAccessToken", "api.oauth.get_access_token.redirect_uri.app_error", nil, "", http.StatusBadRequest)
     		}
     
    -		if code != utils.HashSha256(fmt.Sprintf("%v:%v:%v:%v", clientId, redirectUri, authData.CreateAt, authData.UserId)) {
    -			return nil, model.NewAppError("GetOAuthAccessToken", "api.oauth.get_access_token.expired_code.app_error", nil, "", http.StatusBadRequest)
    -		}
    -
     		if result := <-Srv.Store.User().Get(authData.UserId); result.Err != nil {
     			return nil, model.NewAppError("GetOAuthAccessToken", "api.oauth.get_access_token.internal_user.app_error", nil, "", http.StatusNotFound)
     		} else {
    
  • app/session.go+9 0 modified
    @@ -164,6 +164,15 @@ func RevokeSessionsForDeviceId(userId string, deviceId string, currentSessionId
     	return nil
     }
     
    +func GetSessionById(sessionId string) (*model.Session, *model.AppError) {
    +	if result := <-Srv.Store.Session().Get(sessionId); result.Err != nil {
    +		result.Err.StatusCode = http.StatusBadRequest
    +		return nil, result.Err
    +	} else {
    +		return result.Data.(*model.Session), nil
    +	}
    +}
    +
     func RevokeSessionById(sessionId string) *model.AppError {
     	if result := <-Srv.Store.Session().Get(sessionId); result.Err != nil {
     		result.Err.StatusCode = http.StatusBadRequest
    
  • webapp/components/authorize.jsx+13 2 modified
    @@ -29,8 +29,13 @@ export default class Authorize extends React.Component {
         }
     
         componentWillMount() {
    +        const clientId = this.props.location.query.client_id;
    +        if (!(/^[a-z0-9]+$/.test(clientId))) {
    +            return;
    +        }
    +
             getOAuthAppInfo(
    -            this.props.location.query.client_id,
    +            clientId,
                 (app) => {
                     this.setState({app});
                 }
    @@ -61,7 +66,13 @@ export default class Authorize extends React.Component {
         }
     
         handleDeny() {
    -        window.location.replace(this.props.location.query.redirect_uri + '?error=access_denied');
    +        const redirectUri = this.props.location.query.redirect_uri;
    +        if (redirectUri.startsWith('https://') || redirectUri.startsWith('http://')) {
    +            window.location.replace(redirectUri + '?error=access_denied');
    +            return;
    +        }
    +
    +        window.location.replace('/error');
         }
     
         render() {
    
8fbbd688ea24

Updates to session revoking in v4

https://github.com/mattermost/mattermostJoramWilanderOct 4, 2017via ghsa
4 files changed · +32 3
  • api4/command_test.go+2 2 modified
    @@ -486,7 +486,7 @@ func TestExecuteCommand(t *testing.T) {
     
     func TestExecuteCommandAgainstChannelOnAnotherTeam(t *testing.T) {
     	th := Setup().InitBasic().InitSystemAdmin()
    -	defer th.TearDown()
    +	defer TearDown()
     	Client := th.Client
     	channel := th.BasicChannel
     
    @@ -509,7 +509,7 @@ func TestExecuteCommandAgainstChannelOnAnotherTeam(t *testing.T) {
     		Trigger:   "postcommand",
     	}
     
    -	if _, err := th.App.CreateCommand(postCmd); err != nil {
    +	if _, err := app.CreateCommand(postCmd); err != nil {
     		t.Fatal("failed to create post command")
     	}
     
    
  • api4/user.go+13 1 modified
    @@ -924,7 +924,19 @@ func revokeSession(c *Context, w http.ResponseWriter, r *http.Request) {
     		return
     	}
     
    -	if err := app.RevokeSessionById(sessionId); err != nil {
    +	var session *model.Session
    +	var err *model.AppError
    +	if session, err = app.GetSessionById(sessionId); err != nil {
    +		c.Err = err
    +		return
    +	}
    +
    +	if session.UserId != c.Params.UserId {
    +		c.SetInvalidUrlParam("user_id")
    +		return
    +	}
    +
    +	if err := app.RevokeSession(session); err != nil {
     		c.Err = err
     		return
     	}
    
  • api4/user_test.go+8 0 modified
    @@ -1882,6 +1882,14 @@ func TestRevokeSessions(t *testing.T) {
     	}
     	CheckNoError(t, resp)
     
    +	th.LoginBasic()
    +
    +	sessions, _ = app.GetSessions(th.SystemAdminUser.Id)
    +	session = sessions[0]
    +
    +	_, resp = Client.RevokeSession(user.Id, session.Id)
    +	CheckBadRequestStatus(t, resp)
    +
     	Client.Logout()
     	_, resp = Client.RevokeSession(user.Id, model.NewId())
     	CheckUnauthorizedStatus(t, resp)
    
  • app/session.go+9 0 modified
    @@ -164,6 +164,15 @@ func RevokeSessionsForDeviceId(userId string, deviceId string, currentSessionId
     	return nil
     }
     
    +func GetSessionById(sessionId string) (*model.Session, *model.AppError) {
    +	if result := <-Srv.Store.Session().Get(sessionId); result.Err != nil {
    +		result.Err.StatusCode = http.StatusBadRequest
    +		return nil, result.Err
    +	} else {
    +		return result.Data.(*model.Session), nil
    +	}
    +}
    +
     func RevokeSessionById(sessionId string) *model.AppError {
     	if result := <-Srv.Store.Session().Get(sessionId); result.Err != nil {
     		result.Err.StatusCode = http.StatusBadRequest
    
affd35071ea1

Updates to session revoking in v4 (#7565)

https://github.com/mattermost/mattermostJoram WilanderOct 4, 2017via ghsa
3 files changed · +30 1
  • api4/user.go+13 1 modified
    @@ -926,7 +926,19 @@ func revokeSession(c *Context, w http.ResponseWriter, r *http.Request) {
     		return
     	}
     
    -	if err := c.App.RevokeSessionById(sessionId); err != nil {
    +	var session *model.Session
    +	var err *model.AppError
    +	if session, err = c.App.GetSessionById(sessionId); err != nil {
    +		c.Err = err
    +		return
    +	}
    +
    +	if session.UserId != c.Params.UserId {
    +		c.SetInvalidUrlParam("user_id")
    +		return
    +	}
    +
    +	if err := c.App.RevokeSession(session); err != nil {
     		c.Err = err
     		return
     	}
    
  • api4/user_test.go+8 0 modified
    @@ -1890,6 +1890,14 @@ func TestRevokeSessions(t *testing.T) {
     	}
     	CheckNoError(t, resp)
     
    +	th.LoginBasic()
    +
    +	sessions, _ = th.App.GetSessions(th.SystemAdminUser.Id)
    +	session = sessions[0]
    +
    +	_, resp = Client.RevokeSession(user.Id, session.Id)
    +	CheckBadRequestStatus(t, resp)
    +
     	Client.Logout()
     	_, resp = Client.RevokeSession(user.Id, model.NewId())
     	CheckUnauthorizedStatus(t, resp)
    
  • app/session.go+9 0 modified
    @@ -173,6 +173,15 @@ func (a *App) RevokeSessionsForDeviceId(userId string, deviceId string, currentS
     	return nil
     }
     
    +func (a *App) GetSessionById(sessionId string) (*model.Session, *model.AppError) {
    +	if result := <-a.Srv.Store.Session().Get(sessionId); result.Err != nil {
    +		result.Err.StatusCode = http.StatusBadRequest
    +		return nil, result.Err
    +	} else {
    +		return result.Data.(*model.Session), nil
    +	}
    +}
    +
     func (a *App) RevokeSessionById(sessionId string) *model.AppError {
     	if result := <-a.Srv.Store.Session().Get(sessionId); result.Err != nil {
     		result.Err.StatusCode = http.StatusBadRequest
    

Vulnerability mechanics

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

References

7

News mentions

0

No linked articles in our index yet.