I've had a few people ask why I didn't post the full Matrix email on my Fedi thread. There are two reasons:

  • It wouldn't fit in 1k characters.
  • Listen carefully:
  • Y'know how "just getting caught cheating on your monogamous partner" isn't the right time to discuss exploring ethical nonmonogamy?

    In a similar vein, asking for information while dismissing a report as "no practical security impact" is still dismissing the goddamn report.

    I excerpted the part of their email where they dismissed my report. That was the part that initiated the immediate disclosure. The inciting turn of phrase.

    It doesn't matter how much you piss on my leg, I'm not going to believe it's raining.

    Matrix has many incentives to lie or mislead. Their leadership includes the CEO of a company whose product is a Matrix client. There's active political talks about the EU investing heavily in Matrix. He's got a vested interest in looking good, even at the expense of doing or even being good.

    On the other hand, I have nothing to gain. If everyone switches to Matrix tomorrow, nothing in my life changes. If Matrix self-implodes and everyone goes back to XMPP tomorrow, nothing in my lfie changes.

    The only things I want are:

  • End-to-end encryption to be better.
  • End-to-end encryption to become ubiquitous for communication protocols and apps.
  • The large tech companies whose business models involve privacy violations and stealing from artists and other creative workers to burn down so gloriously that society forgets the word "billionaire" in twenty years.
  • But what about "don't make perfect the enemy of good"?

    If your cryptography isn't damn near-perfect, it's shit. There aren't many cryptographic solutions that get a C+ in the world. It's either an A, A-, or an F.

    An F in cryptography is aes-js / pyaes, as this Trail of Bits blog by Opal Wright explains:

    Mistakes in cryptography are not a sin, even if they can have a serious impact. They’re simply a fact of life. As somebody once said, “cryptography is nightmare magic math that cares what color pen you use.” We’re all going to get stuff wrong if we stick around long enough to do something interesting, and there’s no reason to deride somebody for making a mistake.

    What matters—what separates carelessness from craftsmanship—is the response to a mistake. A careless developer will write off a mistake as no big deal or insist that it isn’t really a problem—yadda, yadda, yadda. A craftsman will respond by fixing what’s broken, examining their tools and processes, and doing what they can to prevent it from happening again.

    Does this sound familiar?

    Carelessness versus craftsmanship in cryptography

    Two popular AES libraries (aes-js and pyaes) provide dangerous default IVs that lead to key/IV reuse vulnerabilities affecting thousands of projects. One maintainer dismissed the issue, while strongSwan’s maintainer exemplified proper security response by comprehensively fixing the vulnerability in their VPN management tool.

    The Trail of Bits Blog

    Now, am I saying that they're lying or deliberately misleading?

    No. I'm describing the incentives they're operating under!

    This could be entirely subconscious or even unconscious decisionmaking and/or behavior for all I know.

    But it's really suspicious to insist that the specific attack I keep describing is handwaved as "outside our threat model" when their public threat model is so frustratingly incomplete that it might as well just say Cryptography: Vibes.

    I mean, look at it: https://spec.matrix.org/v1.17/appendices/#security-threat-model

    Appendices

    Unpadded Base64 Unpadded Base64 refers to ‘standard’ Base64 encoding as defined in RFC 4648, without “=” padding. Specifically, where RFC 4648 requires that encoded data be padded to a multiple of four characters using = characters, unpadded Base64 omits this padding. For reference, RFC 4648 uses the following alphabet for Base 64: Value Encoding Value Encoding Value Encoding Value Encoding 0 A 17 R 34 i 51 z 1 B 18 S 35 j 52 0 2 C 19 T 36 k 53 1 3 D 20 U 37 l 54 2 4 E 21 V 38 m 55 3 5 F 22 W 39 n 56 4 6 G 23 X 40 o 57 5 7 H 24 Y 41 p 58 6 8 I 25 Z 42 q 59 7 9 J 26 a 43 r 60 8 10 K 27 b 44 s 61 9 11 L 28 c 45 t 62 + 12 M 29 d 46 u 63 / 13 N 30 e 47 v 14 O 31 f 48 w 15 P 32 g 49 x 16 Q 33 h 50 y Examples of strings encoded using unpadded Base64:

    Matrix Specification

    You wanna see a fucking threat model?

    Here: https://github.com/fedi-e2ee/public-key-directory-specification/blob/main/Specification.md#threat-model

    And this is for an ActivityPub service that just stores data in immutable plaintext and serves it over HTTPS!

    public-key-directory-specification/Specification.md at main · fedi-e2ee/public-key-directory-specification

    Specification for a Fediverse Directory Server for Public Keys - fedi-e2ee/public-key-directory-specification

    GitHub

    Is it perfect? No.

    If a threat scenario comes up that I didn't imagine, that means I assume, by default, that we're vulnerable until I prove otherwise.

    @soatok wow, I only just learned about this project through this toot, and to see how much thought you put into this is just awesome. Can't wait for the 1.0.0 of #fedipkd

    https://publickey.directory/

    Public Key Directory - Key Transparency for the Fediverse

    @FlohEinstein Oh, yeah, I talk about it a lot here :D

    https://soatok.blog/2026/01/15/software-assurance-that-warm-and-fuzzy-feeling/ talks about my testing methodology if you're curious

    Software Assurance & That Warm and Fuzzy Feeling - Dhole Moments

    If I were to recommend you use a piece of cryptography-relevant software that I created, how would you actually know if it was any good? Art: Wayward Mutt Trust is, first and foremost, a social pro…

    Dhole Moments
    @[email protected] this is a really great read! So many cases detailed that I had not considered as a user. I can’t wait for this to get adopted!

    @soatok is it supposed to say "indistinguishable from" in assumption 11?

    anyway that is really comprehensive..

    @soatok

    I mean the thread model for fucking is pretty simple, it's literally just STDs

    @sudo200 @soatok You seriously underestimate the scope and creativity of human sexuality.

    @curtmack @soatok

    I'm asexual, what do I know?

    @sudo200
    If you took sex threat modeling seriously though, there’d also be various forms of abuse, overwhelming the partners, various possible forms of physical and mental injuries, the mentioned risk of involuntary procreation, ... to consider and suddenly your back at having cryptography level threat modeling over sex again.

    It’s not cryptographers overthinking this, it’s everyone underthinking it for sanity reasons. I mean visiting a BDSM workshop on “consent” is like a multi-hour threat modeling appreciation session.  
    @soatok

    @curiousicae @sudo200 Kink workshops are serious work

    @soatok
    Absolutely, something about dealing with up-front costs, thinking about what can go wrong and being prepared to handle bad situations as they inevitably sometimes arise anyways, so that you can reap great rewards afterwards.

    ... this was a post entirely and only about sex.   
    @sudo200

    @curiousicae @sudo200 @soatok Honestly I had really bad ideas about a lot of sexual stuff for a very long time until meeting my partner and getting a stronger sense of what consent meant, largely from never having had a framework to understand it prior. It was a very big deal and made me cry a couple times in a good way in feeling empowered.

    @curiousicae @sudo200 @soatok As a kinky person who also takes security seriously... exactly this.

    Kink people aren't overthinking this consent thing, everyone else is underthinking it (and boy does it show in society as a whole...).

    @soatok I don't actually get the things that are in their threat model. They list "Spam". Do I get a bug bounty if I join a server and spam someone?
    @jsmall @soatok It is funny that you highlight that because mjolnir their mod tool hasn’t had antispam.py nor the rest of it updated in 4 years. Yes there was a commit in another .py 2 years ago, but it was just a variable rename and not a bug fix or feature add
    https://github.com/matrix-org/mjolnir/tree/c0ea2daf9ee03dc4e466c19c2bb1da119de19147/synapse_antispam/mjolnir
    mjolnir/synapse_antispam/mjolnir at c0ea2daf9ee03dc4e466c19c2bb1da119de19147 · matrix-org/mjolnir

    A moderation tool for Matrix. Contribute to matrix-org/mjolnir development by creating an account on GitHub.

    GitHub

    @soatok This is comically bad at defining anything at all.

    So many of them aren't even like, threats that I (personally) would expect a protocol to handle? Like maybe there's a way to avoid checks matrix documentation "An attacker could send large volumes of messages to a chatroom with the victim making the chatroom unusable" at that level, but that... that's surely a moderation tooling issue, not anything to do with security? You give users the tools to remedy that problem when it arises. Yet I can't tell by what means that's "addressed" (let's be real, it isn't).

    I imagine not very many people who haven't dug deep into exactly how Matrix works at its core can really look at this appendix and get a remotely decent understanding of what, exactly, is happening other than "yeah these can happen."

    I'm no cryptographer, but similar to your statement of "It's either an A, A-, or an F" rings very true in the power and controls industry. Edge cases cannot exist if they are found - they must be designed to prevent or handled smoothly should it be impossible to actually avoid. The last thing you want is to trigger an unintended operation (UO), especially automatically, with no input from an operator.

    I had to deal with writing some totally janky code to handle a pretty gnarly UO that'd happen whenever there was a failover between two devices that talked to a single human-machine interface. For some GOD FORSAKEN REASON the HMI of choice could be configured to connect to two servers (DNP parlance) but it couldn't maintain an active connection between the two. If it lost connection and had to switch to the other server, a lot of data could be completely overwritten by the HMI since again, for some god forsaken reason analog output values are only set on-input in HMI, and then are fucking zeroed out. When it switched over, it would then re-send the goddamn zeroes.

    I forget how exactly we prevented that from happening, IIRC it boiled down to the controllers storing the analog setpoints separately from the HMI's connection and basically ignoring whatever the HMI sends until it confirms the connection was fully established. It was clunky, there was almost certainly a more elegant solution, but we were strapped for time since this came up mid-commissioning and a proper fix was needed ASAP.

    (at least there's good news, in the most recent version of the HMI that was being a little shit, it can now actually talk to both units at the same time which hopefully theoretically removes that problem in the first place. I don't know, I haven't gotten to work with it, and even if it can talk to both at the same time that doesn't resolve the "sending zero values" UO.)

    anyways good lord that "threat model" from Matrix is garbage. Reading through what I could parse of yours, it's y'know. Actually defined how exactly things could be or are a problem, and how they relate to another. Much better, and also much appreciated since it makes it easier to validate whether the functionality satisfies the model presented and the goals for what can and cannot be done at a protocol/design level.

    @soatok
    “We don't have cryptography in our threat model, because our cryptography cannot be attacked 😎👍” vibes.
    @dzwiedziu I read this toot in the style of George Orwell lol
    @soatok
    The Party line is now that it was always the Party's intention for the toot to be read that way.