ActivityPub: the present state, or why saving the ‘worse is better’ virus is both possible and important

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

In our previous episode, I laid out some personal observations about implementing an AP stack from scratch over the past year. When we started this arduous task, there were only three other AP implementations in progress: Mastodon, Kroeg and PubCrawl (the AP transport for Hubzilla), so it has been a pretty significant journey.

I also described how ActivityPub was a student of the ‘worse is better’ design philosophy. Some people felt a little hurt by this, but they shouldn’t have: after all, UNIX (of which modern Linux and BSD systems are a derivative) is also a student of the ‘worse is better’ philosophy. And much like the unices of yesteryear, ActivityPub right now has a lot of missing pieces. But that’s alright, as long as the participants in this experiment understand the limitations.

For the first time in decades, the success of ActivityPub, in part by way of it’s aggressive adoption of the ‘worse is better’ philosophy (which enabled them to ship something) has made some traction that has inspired people to believe that perhaps we can take back the Web and make it open again. This in itself is a wonderful thing, and we must do our best to seize this opportunity and run with it.

As I mentioned, there have been a huge amount of projects looking to implement AP in some way or other, many not yet in a public stage but seeking guidance on how to write an AP stack. My DMs have been quite busy with questions over the past couple of months about ActivityPub.

Let’s talk about the elephant in the room, actually no not that one.

ActivityPub has been brought this far by the W3C Social CG. This is a Community Group that was chartered by the W3C to advance the Social Web.

While they did a good job at getting some of the best minds into the same room and talking about building a federated social web, a lot of decisions were already predetermined (using as a basis) or left underspecified to satisfy other groups inside W3C. Finally, the ActivityPub specification itself claimed that pure JSON could be used to implement ActivityPub, but the W3C kept pushing for layered specs on top like JSON-LD Linked Data Signatures, a spec that is not yet finalized but depends on JSON-LD.

LDS has a lot of problems, but I already covered them already. You can read about some of those problems by reading up on a mitigation known as Blind Key Rotation. Anyway, this isn’t really about W3C pushing for use of LDS in AP, that is just one illustrated example of trying to bundle JSON-LD and dependencies into ActivityPub to make JSON-LD a defacto requirement.

Because of this bundling issue, we established a new community group, called LitePub, this was meant to be a workspace for people actually implementing ActivityPub stacks so that they could get documentation and support for using ActivityPub without JSON-LD, or using JSON-LD in a safe way. To date, the LitePub community is one of the best resources for asking questions about ActivityPub and getting real answers that can be used in production today.

But to build the next generation of ActivityPub, the LitePub group isn’t enough. Is W3C still interested? Unfortunately, from what I can tell, not really: they are pursuing another system that was developed in house called SOLID, which is built on the Linked Data Platform. Since SOLID is being developed by W3C top brass, I would assume that they aren’t interested in stewarding a new revision of ActivityPub. And why would they be? SOLID is essentially a semantic web retread of ActivityPub, which gives the W3C top brass exactly what they wanted in the first place.

In some ways, I argue that W3C’s perceived disinterest in Social Web technologies other than SOLID largely has to do with fediverse projects having a very luke warm response to JSON-LD and LDS.

The good news is that there have been some initial conversations between a few projects on what a working group to build the next generation of ActivityPub would look like, how it would be managed, and how it would be funded. We will be having more of these conversations over the next few months.

ActivityPub: the present state

In the first blog post, I went into a little detail about the present state of ActivityPub. But is it really as bad as I said?

I am going to break down a few examples of faults in the protocol and talk about their current state as well as what we are doing for short-term mitigations and where we are doing them.

Ambiguous addressing: is it a DM or just a post directly addressed to a circle of friends?

As Osada and Hubzilla started to get attention, Mastodon and Pleroma users started to see weird behavior in their notifications and timelines: messages from people they didn’t necessarily follow which got directly addressed to the user. These are messages sent to a group of selected friends, but can otherwise be forwarded (boosted/repeated/announced) to other audiences.

In other words, they do not have the same semantic meaning as a DM. But due to the way they were addressed, Mastodon and Pleroma saw them as a DM.

Mastodon fixed this issue in 2.6 by adding heuristics: if a message has recipients in both the to and cc fields, then it’s a public message that is addressed to a group of recipients, and not a DM. Unfortunately, Mastodon treats it similarly to a followers-only post and does not infer the correct rights.

Meanwhile, Pleroma and Friendica came up with the idea to add a semantic hint to the message with the litepub:directMessage field. If this is set to true, it should be considered as a direct message. If the field is set to false, then it should be considered a group message. If the field is unset, then heuristics are used to determine the message type.

Pleroma has a branch in progress which adds both support for the litepub:directMessage field as well as the heuristics. It should be landing shortly (it needs a rebase and I need to fix up some of the heuristics).

So overall, the issue is reasonably mitigated at this point.

Fake direction attacks

Several months ago, Puckipedia did some fake direction testing against mainstream ActivityPub implementations. Fake direction attacks are especially problematic because they allow spoofing to happen.

She found vulnerabilities in Mastodon, Pleroma and PixelFed, as well as recently a couple of other fediverse software.

The vulnerabilities she reported in Mastodon, Pleroma and PixelFed have been fixed, but the class of vulnerability as she observes keeps appearing.

In part, we can mitigate this by writing excellent security documentation and referring people to read it. This is something that I hope the LitePub group can do in the future.

But for now, I would say this issue is not fully mitigated.

Leakage caused by Mastodon’s followers-only scope

Software which is directly compatible with the Mastodon followers-only scope have a few problems, I am grouping them together here:

  • New followers can see content that was posted before they were authorized to view any followers-only content
  • Replies to followers-only posts are addressed to their own followers instead of the followers collection of the OP at the time the post was created (which creates metadata leaks about the OP)
  • Software which does not support the followers-only scope can dereference the OP’s followers collection in any way they wish, including interpreting it as as:Public (this is explicitly allowed by the ActivityStreams 2.0 specification, you can’t even make this up)

Mitigation of this is actually incredibly easy, which makes me question why Mastodon didn’t do it to begin with: simply expand the followers collection when preparing to send the message outbound.

An implementation of this will be landing in Pleroma soon to harden the followers-only scope as well as fix followers-only threads to be more usable.

Implementation of this mitigation also brings the followers-only threads to Friendica and Hubzilla in a safe and compatible way: all fediverse software will be able to properly interact with the threads.

The “don’t @ me” problem

Some of this interpretation about Zot may be slightly wrong, it is based on reading the specification for Zot and Zot 6.

Other federated protocols such as DFRN, Zot and Zot 6 provide a rich framework for defining what interactions are allowed with a given message. ActivityPub doesn’t.

DFRN provides UI hints on each object that hint at what may be done with the object, but uses a capabilities system under the hood. Capability enforcement is done by the “feed producer,” which either accepts your request or denies it. If you comment on a post in DFRN, it is the responsibility of the parent “feed producer” to forward your post onward through the network.

Zot uses a similar capabilities system but provides a magic signature in response to consuming the capability, which you then forward as proof of acceptance. Zot 6 uses a similar authentication scheme, except using OpenWebAuth instead of the original Zot authentication scheme.

For ActivityPub, my proposal is to use a system of capability URIs and proof objects that are cross-checked by the receiving server. In terms of the proof objects themselves, cryptographic signatures are not a component of this proof system, it is strictly capability based. Cryptographic verification could be provided by leveraging HTTP Signatures to sign the response, if desired. I am still working out the details on how precisely this will work, and that will probably be the what the next blog post is about.

As a datapoint: in Pleroma, we already use this cross-checking technique to verify objects which have been forwarded to us due to ActivityPub §7.1.2. This allows us to avoid JSON-LD and LDS signatures and is the recommended way to verify forwarded objects in LitePub implementations.

Unauthenticated object fetching

Right now, due to the nature of ActivityPub and the design motivations behind it, fetching public objects is entirely unauthenticated.

This has lead to a few incidents where fediverse users have gotten upset over their posts still arriving at servers they have blocked, since they naturally expect that posts won’t arrive at servers they have blocked.

Mastodon has implemented an extension for post fetching where fetching private posts is authenticated using the HTTP Signature of the user who is fetching the post. This is a possible way of solving the authentication problem: instances can be identified based on which actor signed the request.

However, I don’t think that fetching private posts in this way (instead this should always fail) is a good idea and wouldn’t recommend it. With that said, a more generalized approach based on using HTTP Signatures to fetch public posts could be workable.

But I do not think the AP server should use a random user’s key to sign the requests: instead there should be an AP actor which explicitly represents the whole instance, and the instance actor’s key should be used to sign the fetch requests instead. That way information about individual users isn’t leaked, and signatures aren’t created without the express consent of a random instance user.

Once object fetches are properly authenticated in a way that instances are identifiable, then objects can be selectively disclosed. This also hardens object fetching via third parties such as crawlers.


In this particular blog entry, I discussed why ActivityPub is still the hero we need despite being designed with the ‘worse is better’ philosophy, as well as discussed some early plans for cross-project collaboration on a next generation ActivityPub-based protocol, and discussed a few of the common problem areas with ActivityPub and how we can mitigate them in the future.

And with that, despite the present issues we face with ActivityPub, I will end this by borrowing a common saying from the cryptocurrency community: the future is bright, the future is decentralized.

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.