CVE-2026-6339
Description
Mattermost versions 11.5.x <= 11.5.1, 11.4.x <= 11.4.3 fail to validate the X-Requested-With header on the burn-on-read reveal endpoint which allows an authenticated channel member to force the reveal of a burn-on-read message without recipient consent via a crafted Markdown image tag.. Mattermost Advisory ID: MMSA-2026-00636
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Mattermost fails to validate the X-Requested-With header on the burn-on-read reveal endpoint, allowing an attacker to force a message reveal via a crafted Markdown image tag.
Vulnerability
Mattermost versions 11.5.x up to and including 11.5.1, and 11.4.x up to and including 11.4.3 fail to validate the X-Requested-With header on the burn-on-read reveal endpoint. This allows an authenticated channel member to force the reveal of a burn-on-read message without the recipient's consent by embedding a crafted Markdown image tag that triggers a cross-site request forgery (CSRF) style action [1].
Exploitation
An attacker who is an authenticated member of the target channel can craft a Markdown image tag pointing to the burn-on-read reveal endpoint with the appropriate parameters. When a recipient views the message containing this image tag, the recipient's browser automatically sends a request to that endpoint, revealing the burn-on-read content without the recipient's explicit action. The attacker does not require the recipient to click a link; viewing the message is sufficient [1].
Impact
Successful exploitation bypasses the intended consent mechanism for burn-on-read messages. The attacker gains the ability to read the content of a burn-on-read message that would otherwise require the recipient to manually click to reveal. This is a violation of the expected confidentiality controls for such messages [1].
Mitigation
Mattermost has released security updates to address this vulnerability. Users should upgrade to Mattermost version 11.5.2, 11.4.4, or later as per the advisory MMSA-2026-00636 [1]. No workaround has been documented; applying the fix is the recommended action.
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 products
1- Range: <=11.5.1, <=11.4.3
Patches
1b6a14e162c9cMM-68001 - enforce X-Requested-With header validation on BoR reveal endpoint (#35793) (#35826)
3 files changed · +59 −0
server/channels/api4/post.go+9 −0 modified@@ -1491,6 +1491,15 @@ func rewriteMessage(c *Context, w http.ResponseWriter, r *http.Request) { } func revealPost(c *Context, w http.ResponseWriter, r *http.Request) { + // Enforce X-Requested-With header for cookie-authenticated requests. + if r.Header.Get(model.HeaderAuth) == "" { + if r.Header.Get(model.HeaderRequestedWith) != model.HeaderRequestedWithXML { + c.Err = model.NewAppError("revealPost", "api.post.reveal_post.invalid_request.app_error", + nil, "missing or invalid X-Requested-With header", http.StatusForbidden) + return + } + } + c.RequirePostId() if c.Err != nil { return
server/channels/api4/post_test.go+46 −0 modified@@ -5894,6 +5894,52 @@ func TestRevealPost(t *testing.T) { CheckForbiddenStatus(t, resp) require.Nil(t, revealedPost) }, "user without channel access") + + t.Run("cookie auth without X-Requested-With header should be rejected", func(t *testing.T) { + enableBurnOnReadFeature(th) + + _, client2 := createSecondUser(th.BasicChannel) + post := createBurnOnReadPost(client2, th.BasicChannel) + + // Build a raw HTTP request using cookie-based auth (no Authorization header) + // and without the X-Requested-With header — simulating a passive resource load + revealURL := th.Client.APIURL + "/posts/" + post.Id + "/reveal" + req, err := http.NewRequest("GET", revealURL, nil) + require.NoError(t, err) + + req.AddCookie(&http.Cookie{ + Name: model.SessionCookieToken, + Value: th.Client.AuthToken, + }) + + resp, err := th.Client.HTTPClient.Do(req) + require.NoError(t, err) + defer resp.Body.Close() + require.Equal(t, http.StatusForbidden, resp.StatusCode) + }) + + t.Run("cookie auth with X-Requested-With header should be accepted", func(t *testing.T) { + enableBurnOnReadFeature(th) + + _, client2 := createSecondUser(th.BasicChannel) + post := createBurnOnReadPost(client2, th.BasicChannel) + + // Build a raw HTTP request using cookie-based auth with the X-Requested-With header + revealURL := th.Client.APIURL + "/posts/" + post.Id + "/reveal" + req, err := http.NewRequest("GET", revealURL, nil) + require.NoError(t, err) + + req.AddCookie(&http.Cookie{ + Name: model.SessionCookieToken, + Value: th.Client.AuthToken, + }) + req.Header.Set(model.HeaderRequestedWith, model.HeaderRequestedWithXML) + + resp, err := th.Client.HTTPClient.Do(req) + require.NoError(t, err) + defer resp.Body.Close() + require.Equal(t, http.StatusOK, resp.StatusCode) + }) } func TestCreateBurnOnReadPost(t *testing.T) {
server/i18n/en.json+4 −0 modified@@ -2862,6 +2862,10 @@ "id": "api.post.reveal_post.disabled.app_error", "translation": "Burn-on-read feature is not enabled or requires an Enterprise Advanced license." }, + { + "id": "api.post.reveal_post.invalid_request.app_error", + "translation": "Invalid request: missing or invalid X-Requested-With header." + }, { "id": "api.post.reveal_post.user_not_in_channel.app_error", "translation": "You do not have permission to reveal this post. You must be a member of the channel."
Vulnerability mechanics
Root cause
"Missing validation of the X-Requested-With header on the burn-on-read reveal endpoint allows cross-origin requests to force message reveal without recipient consent."
Attack vector
An authenticated channel member crafts a Markdown image tag pointing to the burn-on-read reveal endpoint (e.g., ``). When another channel member views the message containing this tag, the browser automatically issues a GET request to that URL, including any cookies for the Mattermost origin. Because the reveal endpoint previously did not require the `X-Requested-With` header [CWE-346], the server treats this passive resource load as a legitimate reveal request, triggering the burn-on-read action without the recipient's knowledge or consent.
Affected code
The vulnerable code is in `server/channels/api4/post.go` in the `revealPost` function. The endpoint at `POST /api/v4/posts/{post_id}/reveal` lacked any check for the `X-Requested-With` header, allowing cookie-authenticated cross-origin requests to trigger the burn-on-read reveal.
What the fix does
The patch adds a guard at the top of `revealPost` in `server/channels/api4/post.go` [patch_id=918515] that checks whether the request carries an `Authorization` header. If not (meaning the request relies on cookie-based authentication), the server now requires the `X-Requested-With` header to be set to `XMLHttpRequest`. Requests without this header are rejected with HTTP 403. This prevents browsers from treating the reveal endpoint as a simple cross-origin resource load, since the `X-Requested-With` header cannot be set by a standard `<img>` tag or other passive HTML elements. The corresponding test cases in `post_test.go` confirm that cookie-authenticated requests without the header are rejected while those with the header succeed.
Preconditions
- authAttacker must be an authenticated member of the target channel
- configBurn-on-read feature must be enabled on the Mattermost server
- inputTarget recipient must view a message containing the crafted Markdown image tag
- inputAttacker must know the post ID of a burn-on-read message
Generated on May 20, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
1- mattermost.com/security-updatesnvdVendor Advisory
News mentions
0No linked articles in our index yet.