Thread

Article header

NIP17 Groups Context Injection Attack

It goes like this. You’re in a group with three other people.

Person A says: “Are we going ahead with the purchase?”

One minute later Persons B and C say: “Yes” .

You (Person D) naturally assume Persons B and C are responding to the message from Person A.

In reality what happened is Person A sent a message to persons B and C asking if they like ice cream. This message includes you (Person D) in the group tags but you didn’t see it because Person A purposefully did not deliver it to you. Any rogue client can be configured to do this, and Person A has just such a rogue client.

The clients of persons B and C have to assume it was sent to you too, because they have no way to know otherwise, and the default cannot be that it wasn't sent.

At the same time Person A sends you a message asking “Are we going ahead with the purchase?”. They include Persons B and C in the group tags but their rogue client does not send the message to them. Again, your client has to assume that Persons B and C were sent this too, because what else could it assume?

A minute later, Persons B and C each send “Yes”, and you get those messages, because you’re in the tags as generated by their clients. But you have no idea that this "Yes" is in context of the ice cream and not the decision to go ahead with the purchase. You approve the purchase and Person A has pulled off their little trick.

This of course affects any NIP17-based email system you might create too. Other point to point systems like regular email can mitigate this because there is enough metadata to work with (in-reply-to and references headers, server logs to a degree, etc.). NIP17, in removing every last trace of metadata besides the recipient pubkey (and faking the timestamps on top), leaves itself wide open to this kind of attack. This is along with the fact that these are messages in a flat space, not threaded replies, which prevents defences based on the identification of gaps, though even those defences break the metadata promise.

Most ways you can think of to mitigate context injection of this sort break the metadata promise of NIP17. So either you keep the metadata promise and take the hit on context injection, or you fix context injection and you break the metadata promise. Classic Catch 22. Or Catch 17 if you like.

And if you break the metadata promise you very quickly get back to a space where it would have made more sense to just upgrade the encryption in NIP04 and call it a day. (The 'all this sealing and gift-wrapping was for nothing' scenario.)

Keep in mind that NIP17 groups not being able to add and remove people in the way people normally expect of messaging groups makes them a non-starter in this modern age regardless. At the end of the day it's a faked group state, and all of these issues stem from this fact.

Replies (7)

Great post! I won't pretend to understand the finer technical details of cryptography, but it's always a risk to allow any leeway by way of client implementations to "enforce" security, it shouldn't happen. By design this type of injection is very much an attack and the protocol needs to be able to capture and flag these potentially malicious vectors.
🛡️
> So either you keep the metadata promise and take the hit on context injection, or you fix context injection and you break the metadata promise. You can still use metadata, the “promise” is that its no longer leaked, not that there is no metadata.
I presume you mean that wrapped metadata is still metadata, if so then fair enough. In that case what I mean is the 'exposed metadata promise'. But how would you use the wrapped (unexposed) metadata to mitigate context injection in NIP17 groups as described?
Issues with potential mitigations that don’t expose metadata on the relays. [Forcing every new message to be a reply to an older message and then hashing the in-reply-to message and putting the hash in the rumor, then having the client display some warning like “this person may be responding to a message you haven't received” if the message corresponding to the in-reply hash is not known to the client.] Doesn’t work because it’s a flat space. You cannot force every new message to be a reply to an older message. If people want to explicitly reply to an older message they can, if not then not. (Mostly they won’t.) Also a malicious actor can selectively omit the "parent" message for one specific user. [As above, but hash of the last-seen message for that sender instead.] You’ll be drowning in false positives. People talk over each other all the time. And then there’s latency issues, drafts composed offline, etc., messages will arrive to clients out of order constantly. Security warnings are useless if there are 1,000 false positives for every genuine case of detection. Not only that but the context injection attack still works, the attacker just needs to have one “clean” message before the elicited response. So they drop a clean emoji right after the dirty message and done. (And then it’s even more dangerous as the lack of a warning gives an explicitly false sense of security.) [As above, but a previous-hashes array going back quite far, so vector-clock ish] Many of the same (or similar) issues as above and now every event has a map of the conversation history. Also, you're well on the way to Marmot here. TLDR, keep it in the rumor, relays stays blind, good for privacy, but relays cannot enforce the order and so the attacker is always free to lie to different people simultaneously. As for potential mitigations that do expose metadata on the relays, not sure those are worth exploring, given that the slightest toe-hold always leads to the next toe hold.