If Signal wants to show you a notification with message text, it needs to put it on the screen through an OS service. That service was storing the plaintext on the device.

Through an OS service yes, but not a hosted backend service. Obviously that service has store the notification in plaintext (although everything on an iPhone is encrypted at rest, but notification crypto keys have to stay in active memory for the lock screen to work), otherwise it wouldn’t be able to display the notification text.

Apple support applications sending encrypted notifications, where the OS launches the app the decrypt the notification body locally and pass it back to the OS for display.

I think the idea here is that the notification text was also being put somewhere else that was not really tied to the lifetime of it being shown on screen.

They have to. The device storage is itself encrypted, so the FBI already broke into the phone. When the device is unlocked, notifications are visible by design and therefore available in plain text to the user. The edge case is with disappearing messages, a feature Apple did not build for. The message is intended to be plainly visible to the user, but only for a controlled time on the assumption that the users privileges may eventually be compromised.

This makes for a very odd and specific interaction with a 3rd party feature. Security is a hard problem.

This wasn't a disappearing messages case, this was a case where they had uninstalled Signal entirely, including all their messages. But Apple was storing the received message text from the notification in its local database. I don't think it is edge case, in that if someone uninstalls their Whatsapp or Signal or whatever, or they delete a chat/message within that app, that it should be gone off your phone. The OS storing end to end encrypted message content in notification history for no reason (why store content in a database at all) makes message deletion work differently than most people would expect, so it doesn't feel like an edge case to me.

Signal (at least on iOS) has a setting called "Notification Content" which defaults (unsafely in the light of this bug) to "Name, content, and Actions", but allows you to select either "Name Only" or "No Name or Content".

I assume that "Name only" option results in the push notification only sending "Signal message from Bob", and the "No Name or Content" one only sending "You have a new Signal message" - instead of the whole "Signal message from Bob: Let's rob the bank tomorrow!"

If I could have it work the way I'd prefer, Signal would let me set those Notification Content on a per contact and per chat basis - so I could set my bank robbing crew and group chats to "No Name or Content" while leaving mom and the family group chat on "Name, content, and Actions".

(But realistically, if I _did_ have a bank robbing crew they'd all be on my burner phone, not the phone I do family group chat with.)

This is correct, but my understanding of it is that the push notification (which is not the same thing as the actual "Notification" that is shown on the screen) basically contains a "hey $DEVICE, go talk to $APP_NOTO server they got something for you".

APNS just taps on the device's metaphorical shoulder and hands them a courtesy phone "call for you sir"

That’s not how it works. Not on iOS anyway.

For a standard notification the content of that notification is sent through the push notification servers. This includes the title, text, icon, grouping, and sound presets to use. The majority of user-visible notifications are sent this way - the app on the device does not run.

That allows the OS to display your notification without ever running the app, which saves limited resources on the phone. Originally this was the only option, a push notification couldn’t start your app.

These days an app can also register a notification extension which is a standalone program that can modify the incoming notification. It has 30 seconds to do whatever it needs to, though you need to be careful with RAM use or the OS will kill the process and present the notification unaltered. Generally you’d put something generic in the push as a fallback.

There’s also background notifications. These let the app run for 30 seconds and the app can post a local notification during this time, but they’re not guaranteed to be delivered. The OS can decide the system doesn’t have the resources and defer or drop them, or terminate the app before it’s finished if the ram is needed elsewhere.

There are some other special cases depending on what your app does.

> the app on the device does not run.

That explains an oddity I was experiencing.

Work uses Webex. I had work webex installed on my phone. My password changed on my account in the office, if i try to open Webex on my phone I would be prompted to re-authenticate which I would never do because it required 2FA and the token generator is on my laptop which I generally wouldn't have with me when using my phone.

However, despite not being able to open the app as my account, I was still getting full messages in the push notification for anyone who had messaged me recently while the app was functioning. Anyone new would pop up as 'Message From X'.

More details are documented in the ntfy docs: https://docs.ntfy.sh/config/#ios-instant-notifications

Yes, but that service is running locally.

> it needs to put it on the screen through an OS service. That service was storing the plaintext on the device.

Technically, so can the OS's text drawing primitive while drawing Signal's UI.

Yes, but it shouldn't ;)