ActivityPub: The “Worse Is Better” Approach to Federated Social Networking

This is the first article in a series that will be a fairly critical review of ActivityPub from a trust & safety perspective. Stay tuned for more.

In the modern day, myself and many other developers working on libre software have been exposed to a protocol design philosophy that emphasizes safety and correctness. That philosophy can be summarized with these goals:

  • Simplicity: the protocol must be simple to implement. It is more important for the protocol to be simple than the backend implementation.
  • Correctness: the protocol must be verifiably correct. Incorrect behavior is simply not allowed.
  • Safety: the protocol must be designed in a way that is safe. Behavior and functionality which risks safety is considered incorrect.
  • Completeness: the protocol must cover as many situations as is practical. All reasonably expected cases must be covered. Simplicity is not a valid excuse to reduce completeness.

Most people would correctly refer to these as good characteristics and overall the right way to approach designing protocols, especially in a federated and social setting. In many ways, the Diaspora protocol could be considered as an example of this philosophy of design.

The “worse is better” approach to protocol design is only slightly different:

  • Simplicity: the protocol must be simple to implement. It is important for the backend implementation to be equally simple as the protocol itself. Simplicity of both implementation and protocol are the most important considerations in the design.
  • Correctness: the protocol must be correct when tested against reasonably expected cases. It is more important to be simple than correct. Inconsistencies between real implementations and theoretical implementations are acceptable.
  • Safety: the protocol must be safe when tested against basic use cases. It is more important to be simple than safe.
  • Completeness: the protocol must cover reasonably expected cases. It is more important for the protocol to be simple than complete. Under-specification is acceptable when it improves the simplicity of the protocol.

OStatus and ActivityPub are examples of the “worse is better” approach to protocol design. I have intentionally portrayed this design approach in a way to attempt to convince you that it is a really bad approach.

However, I do believe that this approach, even though it is considerably worse approach to protocol design which creates technologies that people simply cannot trust or have confidence in their safety while using those technologies, has better survival characteristics.

To understand why, we have to look at both what expected security features of federated social networks are, and what people mostly use social networks for.

When you ask people what security features they expect of a federated social networking service such as Mastodon or Pleroma, they usually reply with a list like this:

  • I should be able to interact with my friends.
  • The messages I share only with my friends should be handled in a secure manner. I should be able to depend on the software to not compromise my private posts.
  • Blocking should work reasonably well: if I block someone, they should disappear from my experience.

These requirements sound reasonable, right? And of course, ActivityPub mostly gets the job done. After all, the main use of social media is shitposting, posting selfies of yourself and sharing pictures of your dog. But would they be better served by a different protocol? Absolutely.

See, the thing is, ActivityPub is like a virus. The protocol is simple enough to implement that people can actually do it. And they are, aren’t they? There’s over 40 applications presently in development that use ActivityPub as the basis of their networking stack.

Why is this? Because, despite the design flaws in ActivityPub, it is generally good enough: you can interact with your friends, and in compliant implementations, addressing ensures that nobody else except for those you explicitly authorize will read your messages.

But it’s not good enough: for example, people have expressed that they want others to be able to read messages, but not reply to them.

Had ActivityPub been a capability-based system instead of a signature-based system, this would never have been a concern to begin with: replies to the message would have gone to a special capability URI and then accepted or rejected.

There are similar problems with things like the Mastodon “followers-only” posts and general concerns like direct messaging: these types of messages imply specific policy, but there is no mechanism in ActivityPub to convey these semantics. (This is in part solved by the LitePub litepub:directMessage flag, but that’s a kludge to be honest.)

I’ve also mentioned before that a large number of instances where there have been discourse about Mastodon verses Pleroma have actually been caused by complete design failures of ActivityPub.

An example of this is with instances you’ve banned being able to see threads from your instance still: what happens with this is that somebody from a third instance interacts with the thread and then the software (either Mastodon or Pleroma) reconstructs the entire thread. Since there is no authentication requirement to retrieve a thread, these blocked instances can successfully reconstruct the threads they weren’t allowed to receive in the first place. The only difference between Mastodon and Pleroma here is that Pleroma allows the general public to view the shared timelines without using a third party tool, which exposes the leaks caused by ActivityPub’s bad design.

In an ideal world, the number of ActivityPub implementations would be zero. But of course this is not an ideal world, so that leaves us with the question: “where do we go from here?”

And honestly, I don’t know how to answer that yet. Maybe we can save ActivityPub by extending it to be properly capability-based and eventually dropping support for the ActivityPub of today. But this will require coordination between all the vendors. And with 40+ projects out there, it’s not going to be easy. And do we even care about those 40+ projects anyway?


The Case For Blind Key Rotation

ActivityPub uses cryptographic signatures, mainly for the purpose of authenticating messages. This is largely for the purpose of spoofing prevention, but as any observant person would understand, digital signatures carry strong forensic value.

Unfortunately, while ActivityPub uses cryptographic signatures, the types of cryptographic signatures to use have been left unspecified. This has lead to various implementations having to choose on their own which signature types to use.

The fediverse has settled on using not one but two types of cryptographic signature:

  • HTTP Signatures: based on an IETF internet-draft, HTTP signatures provide a cryptographic validation of the headers, including a Digest header which provides some information about the underlying object. HTTP Signatures are an example of detached signatures. HTTP Signatures also generally sign the Date header which provides a defacto validity period.
  • JSON-LD Linked Data Signatures: based on a W3C community draft, JSON-LD Linked Data Signatures provide an inline cryptographic validation of the JSON-LD document being signed. JSON-LD Linked Data Signatures are commonly referred to as LDS signatures or LDSigs because frankly the title of the spec is a mouthful. LDSigs are an example of inline signatures.

Signatures and Deniability

When we refer to deniability, what we’re talking about is forensic deniability, or put simply the ability to plausibly argue in a court or tribunal that you did not sign a given object. In essence, forensic deniability is the ability to argue plausible deniability when presented with a piece of forensic evidence.

Digital signatures are by their very nature harmful with regard to forensic deniability because they are digital evidence showing that you signed something. But not all signature schemes are made equal, some are less harmful to deniability than others.

A good signature scheme which does not harm deniability has the following basic attributes:

  • Signatures are ephemeral: they only hold validity for a given time period.
  • Signatures are revocable: they can be invalidated during the validity period in some way.

Both HTTP Signatures and LDSigs have weaknesses — specifically, both implementations do not allow for the possibility of future revocation of the signature, but LDSigs is even worse because LDSigs are intentionally forever.

Mitigating the revocability problem with Blind Key Rotation

Blind Key Rotation is a mitigation that builds on the fact that ActivityPub implementations must fetch a given actor again in the event that signature authentication fails, by using this fact to provide some level of revocability.

The mitigation works as follows:

  1. You delete one or more objects in a short time period.
  2. Some time after the deletions are processed, the instance rekeys your account. It does not send any Update message or similar because signing your new key with your old key defeats the purpose of this exercise.
  3. When you next publish content, signature validation fails and the instance fetches your account’s actor object again to learn the new keys.
  4. With the new keys, signature validation passes and your new content is published.

It is important to emphasize that in a Blind Key Rotation, you do not send out an Update message with new keys. The reason why this is, is because you do not want to create a cryptographic relationship between the keys. By creating a cryptographic relationship, you introduce new digital evidence which can be used to prove that you held the original keypair at some time in the past.


If you still have questions, contact me on the fediverse:


Pleroma, LitePub, ActivityPub and JSON-LD

A lot of people make assumptions about my position on whether or not JSON-LD is actually good or not. The reality is that my view is more nuanced than that: there are great uses for JSON-LD, but it’s not appropriate in the scenario it is used in ActivityPub.

What is JSON-LD anyway?

JSON-LD stands for JSON Linked Data. Linked Data is a “Big Data” technique which involves creating large graphs of interlinked pieces of data, intended to help enrich data sets with more semantic context (this is known as graph coloring), as well as additional data linked by URI (hince why it’s called linked data). The Linked Data concept can be extremely powerful for data analysis when used in the appropriate context. A good example of where linked data is useful is, where they use it to help compare performance and value verses cost of US health insurance plans.

ActivityPub and JSON-LD

Another example where JSON-LD is ostensibly used is ActivityPub. ActivityPub inherits it’s JSON-LD dependency from ActivityStreams 2.0, which is a data format that enjoys wide use outside of the ActivityPub ecosystem: for example, Twitter, Instagram, Facebook and Tumblr all use variations of ActivityStreams 2.0 objects in various places inside their APIs.

These services find the JSON-LD concept useful because their advertising customers can leverage JSON-LD (in facebook, the open graph concept they frequently pitch to advertisers is built in part on top of JSON-LD) to optimize their advertising campaigns.

But does JSON-LD provide any value in a social networking environment which does not have advertising? In my opinion, not really: it’s just a artifact of the “if you’re not the customer, you’re the product” nature of the proprietary social networking services. As previously stated, the primary advantage of JSON-LD and the linked data philosophy in general is data enrichment, and data enrichment is largely useful to two groups: advertisers and intelligence (public or private).

Since the federated social networking services don’t have advertising, that just leaves intelligence.

Private intelligence and social networking, how data enrichment can impact your credit score

There are various kinds of private intelligence firms out there which collect information about you, me, and everyone else. You’ve probably heard of some of them, and some of the products they sell: companies like Experian, InfoCheckUSA and Equifax sell various products like FICO credit scores and background reports which determine everything from whether or not you can rent or buy a car or house to whether or not you can get a job.

But did you know these companies crawl your use of the proprietary social networking services? There are companies like FriendlyScore which sell credit-related data based on how you utilize social networking services. Those “social” credit scores are directly enabled by technology such as JSON-LD and ActivityStreams 2.0.

Public intelligence and social networking, how data enrichment can get you killed

We’ve all heard about Predator drones and drone strikes in the news. In the past decade, drone strikes have been used to attack countless targets. But how do our public intelligence agencies determine who is a target? It’s very similar to how the private intelligence agencies determine whether you should own a house or have a job: they use big data methods to analyze all of the metadata they collected.

If you write a post on a social networking service and attach GPS data to it, they can use that information to determine a general pattern of when and where you are, and then feed it into a machine learning algorithm to determine when and where you will likely be in the future. They can also use this metadata analysis to prove certain assertions about your identity to a level of certainty which determines if you become a target, even if you’re not really the same person they are trying to find.

Conclusion: safety is more important than data enrichment

These techniques that are used both in the public and private sector are what the press tend to refer to as “Big Data” techniques. JSON-LD is a “Big Data” technology that can be leveraged in these ways. But at the same time, we can leverage some “Big Data” techniques in such a way that JSON-LD parsers will automatically do what we want them to do.

In my opinion, it is a critical obligation of federated social networking service developers to ensure that handling of data is done in the most secure way possible, built on proven fundamentals. I view the inclusion of JSON-LD in the ActivityPub and ActivityStreams 2.0 standards to be harmful toward that obligation.

Pleroma and JSON-LD

As you may know, there are two mainstream ActivityPub servers that are in wide use: Mastodon and Pleroma. Mastodon uses JSON-LD and Pleroma does not. But they are able to interoperate just fine despite this. This is largely because Pleroma provides JSON-LD attributes in the messages it generates without actively using them itself.

Handling ActivityPub in a world without JSON-LD

The origin of the Transmogrifier name

Instead, Pleroma has a module called Transmogrifier that translates between real ActivityPub and our ActivityPub internal representation. The use of AP constructs in our internal representation is the origin of the statement that Pleroma uses ActivityPub internally, and to an extent it is a very truthful statement: our internal representation and object graph are directly derived from an earlier ActivityPub draft, but it’s not quite the same, and there have been a few bugs where things have not been translated correctly which have resulted in leaks and other problems.

Besides the Transmogrifier, we have two functions which fetch new pieces into the graphs we build: Object.normalize() and Activity.normalize(). This could be considered to be a similar approach to JSON-LD except that it’s explicit instead of implicit. The explicit fetching of new graph pieces is a security feature: it allows us to validate that we actually trust what we’re fetching before we do it. This helps us to prevent various “fake direction” attacks which can be used for spoofing.

LitePub and JSON-LD

LitePub is a recent initiative that was started between Pleroma and a few other ActivityPub implementations to slim down the ActivityPub standard into something that is minimalist and secure. While LitePub itself does not require JSON-LD, LitePub implementations follow some JSON-LD like behaviors where it makes sense, and LitePub provides a @context which allows JSON-LD parsers to transparently parse LitePub messages.

Leveraging Linked Data for Object Capability Enforcement

The main principle LitePub is built on is the use of leveraging the linked data paradigm to perform object capability enforcement. This can work either explicitly (as is done in Pleroma) or implicitly (as is done in Mastodon when parsing a LitePub activity).

We do this by treating every Object ID in LitePub as a capability URI. When processing messages that reference a capability URI, we check to make sure the capability URI is still valid by re-fetching the object. If fetching the object fails, then the capability URI is no longer valid. This prevents zombie activities.

A note on Zombie Activities

There are two primary ways of securing ActivityPub implementations with digital signatures: JSON Linked Data Signatures (LDSigs) and the construction built on HTTP Signatures that is leveraged in LitePub. These can be referred to as inline signatures and transient signatures, respectively.

The problem with inline signatures is that they are valid forever. LDSig signatures have no expiration and have no revocation method. Because of this, if an Object is deleted, it can come back to life. The solution created by the LDSig advocates is to use Tombstone objects for all deletions, but that creates a potential metadata leak that proves a post once existed which harms plausible deniability.

The LitePub approach on the other hand is to treat all objects as capability URIs. This means when an object is deleted, future attempts to access the capability URI fail and thus the object cannot come back to life through boosting or other means.


Hopefully this clarifies my views on JSON-LD and it’s applications in the fediverse. Feel free to ask me questions if you have any.


Do not use or provide DH-AES or DH-BLOWFISH for SASL/IAL authentication

Atheme 7.2 dropped support for the DH-AES and DH-BLOWFISH mechanisms. This was for very good reason.

At the time that DH-BLOWFISH was created, IRC was a very different place… SSL was not ubiquitous, and it was thought that having some lightweight encryption on the authentication exchange might be useful, without opening services to a DoS vector. An initial audit on DH-BLOWFISH found some problems, so a second mechanism, DH-AES was created to get rid of some of them.

However, both of these mechanisms use a small keysize for Diffie-Helman key exchange (256 bits), as previously mentioned by grawity. After the freenode incident, where a user discovered they could DoS atheme by spamming it with DH-BLOWFISH requests, we decided to audit both mechanisms, and determined that they should be removed from the distribution.

The reasons why were:

  1. Users had a strong misconception that the mechanisms provided better security than PLAIN over TLS (they don’t);
  2. Because the DH key exchange is unauthenticated, users may be MITM’d by the IRC daemon;
  3. The session key is half the length as the keyexchange phase, making the entire system weak. DH can only securely provide half the bitspace for the session key as the size of key exchange parameters. Put more plainly: if you use DH with 256-bit parameters, the session key is 128 bits, which is weaker than PLAIN over TLS.
  4. Correcting the key exchange to use 256-bit keys would require rewriting every single implementation anyway.

If you want secure authentication, just use PLAIN over TLS, or use atheme’s experimental family of ECDSA mechanisms, namely ECDSA-NIST256P-CHALLENGE. Yes, it’s based on sec256p1, which is a NIST curve, but it’s acceptable for authentication in most cases, and most cryptography libraries implement the sec256p1 curve. While not perfect, it is still much better than the DH family of mechanisms.

Unfortunately, at least one atheme fork has resurrected this mechanism. Hopefully they remove it, as it should be treated as if it were backdoored, because the level of mistakes made in designing the mechanism would be the same type of mistakes one would introduce if they wanted to backdoor a mechanism.

Update: Unfortunately Anope also implemented these broken mechanisms. Luckily it appears that X3 has not.