# Mini profiler causes 403 on attempt to safe draft when editing PM

**URL:** https://meta.discourse.org/t/mini-profiler-causes-403-on-attempt-to-safe-draft-when-editing-pm/408854
**Category:** Support
**Created:** [July 29, 2026, 7:10pm UTC](https://meta.discourse.org/t/mini-profiler-causes-403-on-attempt-to-safe-draft-when-editing-pm/408854 "2026-07-29T19:10:27Z")
**Posts on this page:** 5
**Page:** 1

<div class="post-metadata">

### Author: ![MichaIng](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/michaing/32/251089_2.png) [@MichaIng](https://meta.discourse.org/u/MichaIng)
#### Post date: [July 29, 2026, 7:10pm UTC](https://meta.discourse.org/t/mini-profiler-causes-403-on-attempt-to-safe-draft-when-editing-pm/408854/1 "2026-07-29T19:10:27Z")

</div>

Since the update to `v2026.8.0-latest +28` (from some `v2026.7`), as “developer”, when editing a PM, I see

![{52B46C2B-8166-4B02-92C9-936558B256BA}](https://global.discourse-cdn.com/meta/original/4X/8/2/6/8269f9001efb5aafbe7879cac1a9dc69a33c5b87.png)

In browser console I see:

```plaintext
20:54:29.425 includes.js?v=e0bcc9ce0ae3bb5d6b736b6f282f601f:840 POST https://dietpi.com/forum/drafts.json 403 (Forbidden)
(anonymous) @ includes.js?v=e0bcc9ce0ae3bb5d6b736b6f282f601f:840
send @ jquery.js:9940
ajax @ jquery.js:9521
i @ ajax.js:233
Z @ ajax.js:252
save @ draft.js:37
saveDraft @ composer.js:1535
_saveDraft @ composer.js:1963
_shouldSaveDraft @ composer.js:1999
sendEvent @ cache-DtDz7X5V.js:471
(anonymous) @ cache-DtDz7X5V.js:665
invoke @ index.js:262
flush @ index.js:180
flush @ index.js:334
_end @ index.js:762
(anonymous) @ index.js:499
Promise.then
(anonymous) @ index.js:18
flush @ index.js:29
_scheduleAutorun @ index.js:928
_end @ index.js:768
(anonymous) @ index.js:499
Promise.then
(anonymous) @ index.js:18
flush @ index.js:29
_scheduleAutorun @ index.js:928
_end @ index.js:768
(anonymous) @ index.js:499
Promise.then
(anonymous) @ index.js:18
flush @ index.js:29
_scheduleAutorun @ index.js:928
_end @ index.js:768
(anonymous) @ index.js:499
Promise.then
(anonymous) @ index.js:18
flush @ index.js:29
_scheduleAutorun @ index.js:928
_end @ index.js:768
(anonymous) @ index.js:499
Promise.then
(anonymous) @ index.js:18
flush @ index.js:29
_scheduleAutorun @ index.js:928
_ensureInstance @ index.js:919
ensureInstance @ index.js:731
scheduleRevalidate @ index-DaCZcoCY.js:4146
dirtyTag @ index.js:229
dirtyTagFor @ index.js:848
setter @ index.js:871
set @ cache-DtDz7X5V.js:1886
_setProp @ property_set-n9lAuzYY.js:47
set @ property_set-n9lAuzYY.js:42
(anonymous) @ set_properties-D2_u0phU.js:94
changeProperties @ cache-DtDz7X5V.js:802
(anonymous) @ set_properties-D2_u0phU.js:88
setProperties @ observable.js:30
_hydrate @ store.js:446
_hydrateFindResults @ store.js:106
(anonymous) @ store.js:124
Promise.then
find @ store.js:123
(anonymous) @ composer.js:1110
mu @ rsvp-ziM3qQyS.js:412
(anonymous) @ rsvp-ziM3qQyS.js:468
invoke @ index.js:264
flush @ index.js:180
flush @ index.js:334
_end @ index.js:762
end @ index.js:565
_runExpiredTimers @ index.js:869
setTimeout
setTimeout @ index.js:39
_installTimerTimeout @ index.js:912
_reinstallTimerTimeout @ index.js:896
_later @ index.js:829
later @ index.js:652
next @ index.js:562
_triggerAction @ d-button.gts:212
click @ d-button.gts:166
20:54:31.380 includes.js?v=e0bcc9ce0ae3bb5d6b736b6f282f601f:840 POST https://dietpi.com/forum/drafts.json 403 (Forbidden)
(anonymous) @ includes.js?v=e0bcc9ce0ae3bb5d6b736b6f282f601f:840
send @ jquery.js:9940
ajax @ jquery.js:9521
i @ ajax.js:233
Z @ ajax.js:252
save @ draft.js:37
saveDraft @ composer.js:1535
_saveDraft @ composer.js:1963
invoke @ index.js:264
flush @ index.js:180
flush @ index.js:334
_end @ index.js:762
end @ index.js:565
_runExpiredTimers @ index.js:869
setTimeout
setTimeout @ index.js:39
_installTimerTimeout @ index.js:912
_scheduleExpiredTimers @ index.js:892
_runExpiredTimers @ index.js:868
setTimeout
setTimeout @ index.js:39
_installTimerTimeout @ index.js:912
_scheduleExpiredTimers @ index.js:892
_runExpiredTimers @ index.js:868
setTimeout
setTimeout @ index.js:39
_installTimerTimeout @ index.js:912
_scheduleExpiredTimers @ index.js:892
_runExpiredTimers @ index.js:868
setTimeout
setTimeout @ index.js:39
_installTimerTimeout @ index.js:912
_scheduleExpiredTimers @ index.js:892
_runExpiredTimers @ index.js:868
setTimeout
setTimeout @ index.js:39
_installTimerTimeout @ index.js:912
_reinstallTimerTimeout @ index.js:896
_later @ index.js:829
debounce @ index.js:680
debounce @ index.js:713
(anonymous) @ debounce.js:26
debouncedRecalculateHeaderOffset @ glimmer-site-header.gjs:96
_run @ index.js:804
_join @ index.js:783
join @ index.js:605
join @ index.js:152
(anonymous) @ index.js:250
20:54:34.397 7:1 The resource https://dietpi.com/matomo/matomo.js was preloaded using link preload but not used within a few seconds from the window's load event. Please make sure it has an appropriate `as` value and it is preloaded intentionally.
20:54:39.457 7:1 The resource https://dietpi.com/matomo/matomo.js was preloaded using link preload but not used within a few seconds from the window's load event. Please make sure it has an appropriate `as` value and it is preloaded intentionally.

```

This 403 seems to be coming from the mini profiler:

```plaintext
    if (!window.MiniProfiler || !window.MiniProfiler.patchesApplied) {
      var send = XMLHttpRequest.prototype.send;

      XMLHttpRequest.prototype.send = function(data) {
        ajaxStartTime = new Date();
        this.addEventListener("load", function() {
          // responseURL isn't available in IE11
          if (
            this.responseURL &&
            this.responseURL.indexOf(window.location.origin) !== 0
          ) {
            return;
          }
          if (this.__miniProfilerSkipResultsFetch) {
            return;
          }
          // getAllResponseHeaders isn't available in Edge.
          var allHeaders = this.getAllResponseHeaders
            ? this.getAllResponseHeaders()
            : null;
          if (
            allHeaders &&
            allHeaders.toLowerCase().indexOf("x-miniprofiler-ids") === -1
          ) {
            return;
          }
          // should be a string of comma-separated ids
          var stringIds = this.getResponseHeader("X-MiniProfiler-Ids");

          if (stringIds) {
            var ids = stringIds.split(",");
            fetchResults(ids);
          }
        });
        send.call(this, data);
      }; // fetch results after ASP Ajax calls

```

The `send.call(this, data)` is what receives 403 when trying to send a POST to `drafts.json`, as far as I understand. I suppose the `data` is garbage, causing the 403? There is no info in browser about some CSP or other security rule/header blocking any request.

This does not happen when editing a public post, or adding a new PM to a conversation, just when editing a post in a PM conversation.

Hiding the profiler via ALT+P does not prevent this. I should probably test it as non-developer user.

As a result of that error, I suppose, saving the edit fails as well, since the data is no valid JSON.

We use the official Docker container, but, as can be seen, run it behind a proxy (Apache2) on the `/forum` sub path. Probably this has an effect.

---

<div class="post-metadata">

### Author: ![MichaIng](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/michaing/32/251089_2.png) [@MichaIng](https://meta.discourse.org/u/MichaIng)
#### Post date: [July 29, 2026, 7:24pm UTC](https://meta.discourse.org/t/mini-profiler-causes-403-on-attempt-to-safe-draft-when-editing-pm/408854/2 "2026-07-29T19:24:01Z")

</div>

Ah, it was just a Cloudflare firewall false positive, `95a84ab1645a49c685648c17761e7a4c` of the “Cloudflare Managed Ruleset”, if someone else stumbles onto it. This is already the 7th rule among their default ruleset that I needed to disable for Discourse, as it scans JSON content, hence the content of posts, for certain pattern. As I write/paste often shell (and other) code, these rules kick in.

---

<div class="post-metadata">

### Author: ![riking](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/riking/32/170938_2.png) [@riking](https://meta.discourse.org/u/riking)
#### Post date: [July 31, 2026, 8:15pm UTC](https://meta.discourse.org/t/mini-profiler-causes-403-on-attempt-to-safe-draft-when-editing-pm/408854/3 "2026-07-31T20:15:56Z")

</div>

Discourse can generally run without any WAF filtering at all, the security process is very robust and basically never has the kind of problems that WAFs are developed to protect.

---

<div class="post-metadata">

### Author: ![MichaIng](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/michaing/32/251089_2.png) [@MichaIng](https://meta.discourse.org/u/MichaIng)
#### Post date: [July 31, 2026, 8:41pm UTC](https://meta.discourse.org/t/mini-profiler-causes-403-on-attempt-to-safe-draft-when-editing-pm/408854/4 "2026-07-31T20:41:14Z")

</div>

That may be right. However, I prefer the conservative approach to disable individual rules if I see them kicking in as false positive. This case reminds me to always check this first, if I see some 403 after a Discourse update, or in general.

But I agree, given that this was one new of overall 7 (for Discourse) problematic rules, and that we did already disable a lot of enabled-by-default rules domain-wide, for software we do not use, fiddling with this is a continuous maintenance. So for most admins, disabling the managed WAF rules (for Discourse host/path) altogether is probably the only practical solution.

For completeness, here the rules we need to exclude. As can be seen, mostly command injection false positives based on post text content:

 ![{76363059-6E8F-4522-A0C8-F847FE80023A}](https://global.discourse-cdn.com/meta/original/4X/2/3/1/23183e3105b7f0f200df8aee3cd4c6e3d05a101d.png)

---

<div class="post-metadata">

### Author: ![system](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/system/32/443519_2.png) [@system](https://meta.discourse.org/u/system)
#### Post date: [August 30, 2026, 8:41pm UTC](https://meta.discourse.org/t/mini-profiler-causes-403-on-attempt-to-safe-draft-when-editing-pm/408854/5 "2026-08-30T20:41:48Z")

</div>

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.
