[bug] User unable to respond to a private post while being tagged #1135

Open
opened 2026-06-02 10:28:15 +00:00 by domi · 8 comments

Your setup

OTP

Extra details

No response

Version

3.19.0-0-g4ceb81a--stable-

PostgreSQL version

17

What were you trying to do?

As mentioned on IRC - one of my users has gotten two separate instances of "Must be able to access post to interact with it" in one day, both of which towards a status with locked visibility where they were mentioned, but weren't following whoever mentioned them.

  • incident_A0.json, incident_B0.json: previous posts in the threads, for context
  • incident_A1.json, incident_B1.json: posts they tried replying to, but couldn't due to the error

Quite curiously, said posts did display in the instance UI just fine (I have screenshots of both incidents). FYI: We're lagging with FE updates because I didn't have enough spoons to rebase our changeset, but i don't think that's related?

What did you expect to happen?

No response

What actually happened?

No response

Logs

No response

Severity

I cannot use the software

Have you searched for this issue?

  • I have double-checked and have not found this issue mentioned anywhere.
### Your setup OTP ### Extra details _No response_ ### Version 3.19.0-0-g4ceb81a--stable- ### PostgreSQL version 17 ### What were you trying to do? As mentioned on IRC - one of my users has gotten two separate instances of "Must be able to access post to interact with it" in one day, both of which towards a status with locked visibility where they were mentioned, but weren't following whoever mentioned them. - incident_A0.json, incident_B0.json: previous posts in the threads, for context - incident_A1.json, incident_B1.json: posts they tried replying to, but couldn't due to the error Quite curiously, said posts did display in the instance UI just fine (I have screenshots of both incidents). FYI: We're lagging with FE updates because I didn't have enough spoons to rebase our changeset, but *i don't think* that's related? ### What did you expect to happen? _No response_ ### What actually happened? _No response_ ### Logs _No response_ ### Severity I cannot use the software ### Have you searched for this issue? - [x] I have double-checked and have not found this issue mentioned anywhere.
Owner

Can you also share the (censored if necessary; just keep the addressing fields (*to, *cc) in data and the recipients db column intact) Create activity stored in the database for the posts replying to failed?

These fields too affect what is visible (usually it should match the content in the object and i believe we added a processing step to enforce this some months ago, but sth might have gone wrong or this normalisation was skipped)

Can you also share the *(censored if necessary; just keep the addressing fields (`*to`, `*cc`) in `data` and the `recipients` db column intact)* `Create` activity stored in the database for the posts replying to failed? These fields too affect what is visible *(_usually_ it should match the content in the object and i believe we added a processing step to enforce this some months ago, but sth might have gone wrong or this normalisation was skipped)*
Author
id | data | inserted_at | updated_at | local | actor | recipients 

0000019e-8497-e20a-c088-131353500000 | {"cc": [], "id": "https://berkeley.edu.pl/activities/d7d568e4-c5e2-4faa-ab56-455db85c1ae9", "to": ["https://berkeley.edu.pl/users/noisytoot/followers", "https://chaos.social/users/manawyrm"], "bcc": [], "bto": [], "type": "Create", "actor": "https://berkeley.edu.pl/users/noisytoot", "object": "https://berkeley.edu.pl/objects/d2c465c2-f9be-468f-9144-283c837a03a3", "context": "https://chaos.social/contexts/103523-116658192731749011"} | 2026-06-01 19:10:06 | 2026-06-01 19:10:06 | f     | https://berkeley.edu.pl/users/noisytoot | {https://berkeley.edu.pl/users/noisytoot/followers,https://chaos.social/users/manawyrm,https://berkeley.edu.pl/users/noisytoot}

0000019e-8521-0c8d-c088-131353500000 | {"cc": [], "id": "https://fe.disroot.org/activities/76f48d92-7f0f-426f-89ac-fd8ece1a3c0c", "to": ["https://fe.disroot.org/users/moses_izumi/followers"], "bcc": [], "bto": [], "type": "Create", "actor": "https://fe.disroot.org/users/moses_izumi", "object": "https://fe.disroot.org/objects/a647cd75-64e2-4be8-a03c-d8ffc76b10c5", "context": "https://donotsta.re/contexts/07ac935f-6031-4848-adb7-6ea9d968b842"} | 2026-06-01 21:39:56 | 2026-06-01 21:39:56 | f     | https://fe.disroot.org/users/moses_izumi | {https://fe.disroot.org/users/moses_izumi/followers,https://fe.disroot.org/users/moses_izumi}

is this the data you wanted, or did I query the wrong object?

``` id | data | inserted_at | updated_at | local | actor | recipients 0000019e-8497-e20a-c088-131353500000 | {"cc": [], "id": "https://berkeley.edu.pl/activities/d7d568e4-c5e2-4faa-ab56-455db85c1ae9", "to": ["https://berkeley.edu.pl/users/noisytoot/followers", "https://chaos.social/users/manawyrm"], "bcc": [], "bto": [], "type": "Create", "actor": "https://berkeley.edu.pl/users/noisytoot", "object": "https://berkeley.edu.pl/objects/d2c465c2-f9be-468f-9144-283c837a03a3", "context": "https://chaos.social/contexts/103523-116658192731749011"} | 2026-06-01 19:10:06 | 2026-06-01 19:10:06 | f | https://berkeley.edu.pl/users/noisytoot | {https://berkeley.edu.pl/users/noisytoot/followers,https://chaos.social/users/manawyrm,https://berkeley.edu.pl/users/noisytoot} 0000019e-8521-0c8d-c088-131353500000 | {"cc": [], "id": "https://fe.disroot.org/activities/76f48d92-7f0f-426f-89ac-fd8ece1a3c0c", "to": ["https://fe.disroot.org/users/moses_izumi/followers"], "bcc": [], "bto": [], "type": "Create", "actor": "https://fe.disroot.org/users/moses_izumi", "object": "https://fe.disroot.org/objects/a647cd75-64e2-4be8-a03c-d8ffc76b10c5", "context": "https://donotsta.re/contexts/07ac935f-6031-4848-adb7-6ea9d968b842"} | 2026-06-01 21:39:56 | 2026-06-01 21:39:56 | f | https://fe.disroot.org/users/moses_izumi | {https://fe.disroot.org/users/moses_izumi/followers,https://fe.disroot.org/users/moses_izumi} ``` is this the data you wanted, or did I query the wrong object?
Owner

This is the correct data, yes :)

Those posts are odd cases in slightly different ways and given one of them originates from another Akkoma instance, might be also an additional sending bug on our side.

Both of them do not list the affects dns account in the addressing field, neither in the object nor activity, only a tag "mention". By standard AP semantics the affected user should never see this post and our API checks should prevent this.
I lack the time to properly trace and test it, but my guess is that if this is actually queried from the API via GET /api/v1/statuses/XXX it will already return a 404 and the post only shows up in the fronted because the presumably our notification generator or so mistakenly relies on tagged mentions without cross-verifying this with the actual AP addressing. (Does the affected user use push notifications, the streaming API (real-time updates) or only active API polling?)

For the post from a Pleroma instance (B1), you can see in the formerRepresentations, that the affected account used to be addressed in to but no longer is in the edited/updated version.
Curiously, the activity does not address them, but i don’t think we currently update the Create activity’s addressing on Update activities (and certainly not on active refreshes, which incidentally i fixed locally just a few days ago but haven't pushed yet).
EIther we do this afterall for Update activities, or somehow the "copy addressing from object to activity" step of the inbox pipeline wasn’t executed.
The addressing disappearing on edit might be a Pleroma bug (maybe Akkoma too?), or perhaps there’s some bizarre ancient thing hidden somewhere in our processing inserting mentioned users into to, but only for the initial Create and only the object after addressing was already synced between the two. (Do you run custom MRFs or any built-in MRF which might be related?)

The other post from another Akkoma instance (A1), does not show an edit history so it must already have been missing on initial posting. We do have an "explicit addressing" feature which allows mentioning @handles inline without addressing those accounts though it’s not exposed in akkoma-fe atm. Either the author runs some other FE and accidentally turned on this mode, or there’s some bug in our sending code.

I guess, just to make sure the to addressing wasn’t stripped somehow during our incoming processing it would be good to also check the raw canonical representation of the posts on the source instances. But atm there’s now good way to fetch with user keys, even when using a remote elixir shell and if the addressing is missing, it couldn’t be fetched anyway...

This is the correct data, yes :) Those posts are odd cases in slightly different ways and given one of them originates from another Akkoma instance, might be also an additional _sending_ bug on our side. Both of them _do not list the affects dns account in the addressing field, neither in the object nor activity_, only a tag "mention". By standard AP semantics the affected user should _never_ see this post and our API checks _should_ prevent this. I lack the time to properly trace and test it, but my guess is that if this is actually queried from the API via `GET /api/v1/statuses/XXX` it will already return a 404 and the post only shows up in the fronted because the presumably our notification generator or so mistakenly relies on tagged mentions without cross-verifying this with the actual AP addressing. *(Does the affected user use push notifications, the streaming API (real-time updates) or only active API polling?)* For the post from a Pleroma instance (B1), you can see in the `formerRepresentations`, that the affected account _used_ to be addressed in `to` but no longer is in the edited/updated version. Curiously, the activity does not address them, but i don’t think we currently update the `Create` activity’s addressing on `Update` activities (and certainly not on active refreshes, which incidentally i fixed locally just a few days ago but haven't pushed yet). EIther we do this afterall for `Update` activities, or somehow the "copy addressing from object to activity" step of the inbox pipeline wasn’t executed. The addressing disappearing on edit might be a Pleroma bug (maybe Akkoma too?), or perhaps there’s some bizarre ancient thing hidden somewhere in our processing inserting mentioned users into `to`, but only for the initial Create and only the object after addressing was already synced between the two. *(Do you run custom MRFs or any built-in MRF which might be related?)* The other post from another Akkoma instance (A1), does not show an edit history so it must already have been missing on initial posting. We do have an "explicit addressing" feature which allows mentioning `@handles` inline without addressing those accounts though it’s not exposed in akkoma-fe atm. Either the author runs some other FE and accidentally turned on this mode, or there’s some bug in our sending code. I guess, just to make sure the `to` addressing wasn’t stripped somehow during our incoming processing it would be good to also check the raw canonical representation of the posts on the source instances. But atm there’s now good way to fetch with user keys, even when using a remote elixir shell and if the addressing is missing, it couldn’t be fetched anyway...
Author

Does the affected user use push notifications, the streaming API (real-time updates) or only active API polling?

Incident happened via akko-fe, so most likely streaming API, I'm double-checking with them. Will edit this once I know more. (EDIT: my assumption was correct)

If this matters, user also has Admin rights, but IME the non-admin API still respects most boundaries in this case - mentioning in case this is an edge-case.

Do you run custom MRFs or any built-in MRF which might be related?

We're running ObjectAgePolicy, TagPolicy, SimplePolicy, HellthreadPolicy, RejectNewlyCreatedAccountNotesPolicy, KeywordPolicy. AFAICT none of them should affect the posts in this case. I can share more details about our config if needed.

> Does the affected user use push notifications, the streaming API (real-time updates) or only active API polling? Incident happened via akko-fe, so most likely streaming API, I'm double-checking with them. Will edit this once I know more. (EDIT: my assumption was correct) If this matters, user also has Admin rights, but IME the non-admin API still respects most boundaries in this case - mentioning in case this is an edge-case. > Do you run custom MRFs or any built-in MRF which might be related? We're running ObjectAgePolicy, TagPolicy, SimplePolicy, HellthreadPolicy, RejectNewlyCreatedAccountNotesPolicy, KeywordPolicy. AFAICT none of them should affect the posts in this case. I can share more details about our config if needed.
Author

Another thing I've just noticed which may be semi-related (or a different bug entirely): ever since the last stable update, I'm seeing some @'s fail to tag people on our side

Compare those two views:

Original instance seems to have correctly tagged jagoda, our akko-fe doesn't display it. I've never seen it happen until a few days ago, now this is at least the 2nd time I see this. What gives?

Another thing I've just noticed which may be semi-related (or a different bug entirely): ever since the last stable update, I'm seeing some @'s fail to tag people on our side Compare those two views: - https://blahaj.love/notes/an0ite70nw7902se - https://donotsta.re/notice/B6vlHsjs16n4Bxp3a4 Original instance seems to have correctly tagged jagoda, our akko-fe doesn't display it. I've never seen it happen until a few days ago, now this is at least the 2nd time I see this. What gives?
Owner

We're running […]

yeah, i don’t think those should strip individuals from addressing

Another thing I've just noticed which may be semi-related

This is purely visual. The API response still contains the account in mentions.
Since this is an MFM post and Sharkey doesn’t implement FEP-c16b, we need to reparse the source on our end to get usable HTML and our logic doesn’t recognise the mention. The tagged mentions and addressing are not touched by this.
Linkify generates the mention HTML (after all other Markdown and MFM processing). The last change there i recall actually just made it more lenient (allowing . in usernames). I’m guessing in this case it is tripped up by the " at the end.
Otherwise, the latest related I change otoh is fairly recent: placing the HTML sanitiser always at the very end, also after Linkify. That shoudn’t regress things either though, unless Linkify had an HTML injection bug (none is known).

> We're running […] yeah, i don’t think those should strip individuals from addressing > Another thing I've just noticed which may be semi-related This is purely visual. The API response still contains the account in `mentions`. Since this is an MFM post and Sharkey doesn’t implement FEP-c16b, we need to reparse the source on our end to get usable HTML and our logic doesn’t recognise the mention. The `tag`ged mentions and addressing are not touched by this. `Linkify` generates the mention HTML (after all other Markdown and MFM processing). The last change there i recall actually just made it more lenient *(allowing `.` in usernames)*. I’m guessing in this case it is tripped up by the `"` at the end. Otherwise, the latest related I change otoh is fairly recent: placing the HTML sanitiser always at the very end, also _after_ Linkify. That shoudn’t regress things either though, unless `Linkify` had an HTML injection bug (none is known).
Owner

but my guess is that if this is actually queried from the API via GET /api/v1/statuses/XXX it will already return a 404 and the post only shows up in the fronted because the presumably our notification generator or so mistakenly relies on tagged mentions without cross-verifying this with the actual AP addressing.

Having followed the call path through too many layers of indirections and realising there are two streams for a new object with mentions (one for the object itself, one for the notification with an inlined object): this is indeed what’s happening. Skipping uninteresting middle layers:

The notifications adds all mentioned (tagged) accounts via a util function asserting a to field existing but not using its value.
When the SideEffects module then (..while the transaction is still ongoing and might fail (as brought up about before elsewhere)) initiates pushing out the new object to relevant streams and later (correctly after the transaction succeeded) does the same for the notification.
However, streaming API isn’ŧ even important here, as StreamerView just uses NotificationView, but NotificationView directly calls StatusView’s "show.json" without any checks. The latter takes the viewing user as an argument, but only uses this to fill in some fields, not for deciding whether or not to render anything at all as this is supposed to have already been checked at this point.

This makes some sense since usually everyone who receives a notification about a status should also have perms to view it. However, since it earlier used Mention-typed tag entries as a source, this fails here.
Furthermore however, if we allow remotes changing addressing/visibility: someone may very well initially have had perms to view a status, then lost it after an update, but even so they can still view the current version of the status by requesting the prior notification!


As for *oma’s "explicit addressing" feature, when the API received an explicit to list, this set will be used for both the AP addressing and will be the only source for tagged mentions. Other in-line @handle references will still be processed into clickable links and be styled further by the FE, but will not show up in AP data or API responses as "mentions".
Meaning, at least for this case the current flawed logic won’t actually lead to status leaks (and i’m not aware of any current impl tagging not-actually-addressed accounts). It’s still wrong though and should be fixed.
(And ofc, for these two samples, the tagged but not addressed account appears to have been inteded to be able to view the post.)

However, this also means explicit addressing does not explain the Akkoma-instance sample and there’s probably some sending-side bug lurking. I couldn’t spot anything though while going over ActivityDraft logic. Maybe some MRF on the source server?
It would be great to cross-check the representation on the source instance and if mentions and to addressing diverge there too get details about the active MRFs or how this can be reproduced / which accounts are affected.

Haven’t investigated addressing changes on local edits yet wrt to the Pleroma sample.

> but my guess is that if this is actually queried from the API via GET /api/v1/statuses/XXX it will already return a 404 and the post only shows up in the fronted because the presumably our notification generator or so mistakenly relies on tagged mentions without cross-verifying this with the actual AP addressing. Having followed the call path through too many layers of indirections and realising there are _two_ streams for a new object with mentions (one for the object itself, one for the notification with an inlined object): this is indeed what’s happening. Skipping uninteresting middle layers: The [notifications adds all mentioned (tagged) accounts ](https://akkoma.dev/AkkomaGang/akkoma/src/commit/678f6fdb7819af2af474aab057a34e3bf103c446/lib/pleroma/notification.ex#L530) via [a util function asserting a `to` field existing but not using its value](https://akkoma.dev/AkkomaGang/akkoma/src/commit/678f6fdb7819af2af474aab057a34e3bf103c446/lib/pleroma/web/common_api/utils.ex#L383). When the `SideEffects` module then (..while the transaction is still ongoing and might fail (as brought up about before elsewhere)) [initiates pushing out the new object to relevant streams](https://akkoma.dev/AkkomaGang/akkoma/src/commit/678f6fdb7819af2af474aab057a34e3bf103c446/lib/pleroma/web/activity_pub/side_effects.ex#L246-L251) and later *(correctly after the transaction succeeded)* does the same for the notification. However, streaming API isn’ŧ even important here, as `StreamerView` just uses `NotificationView`, but `NotificationView` directly calls `StatusView`’s `"show.json"` without any checks. The latter takes the viewing user as an argument, but only uses this to fill in some fields, not for deciding whether or not to render anything at all as this is supposed to have already been checked at this point. This makes some sense since _usually_ everyone who receives a notification about a status _should_ also have perms to view it. However, since it earlier used `Mention`-typed `tag` entries as a source, this fails here. Furthermore however, _if_ we allow remotes changing addressing/visibility: someone may very well _initially_ have had perms to view a status, then lost it after an update, but even so they can _still_ view the _current version_ of the status by requesting the prior notification! ---- As for *oma’s "explicit addressing" feature, when the API received an explicit `to` list, this set will be used for _both_ the AP addressing _and_ will be the _only_ source for tagged mentions. Other in-line `@handle` references will still be processed into clickable links and be styled further by the FE, but will not show up in AP data or API responses as "mentions". Meaning, at least for this case the current flawed logic won’t actually lead to status leaks *(and i’m not aware of any current impl tagging not-actually-addressed accounts)*. It’s still wrong though and should be fixed. *(And ofc, for these two samples, the tagged but not addressed account appears to have been _inteded_ to be able to view the post.)* However, this also means explicit addressing does not explain the Akkoma-instance sample and there’s probably some sending-side bug lurking. I couldn’t spot anything though while going over `ActivityDraft` logic. Maybe some MRF on the source server? It would be great to cross-check the representation on the source instance and if mentions and `to` addressing diverge there too get details about the active MRFs or how this can be reproduced / which accounts are affected. Haven’t investigated addressing changes on local edits yet wrt to the Pleroma sample.
Author

It would be great to cross-check the representation on the source instance and if mentions and to addressing diverge there too get details about the active MRFs or how this can be reproduced / which accounts are affected.

I will try to reach out to the remote admins after GPN; ping me if I forget. Thanks heaps for the investigation <3

> It would be great to cross-check the representation on the source instance and if mentions and to addressing diverge there too get details about the active MRFs or how this can be reproduced / which accounts are affected. I will try to reach out to the remote admins after GPN; ping me if I forget. Thanks heaps for the investigation <3
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
AkkomaGang/akkoma#1135
No description provided.