this post was submitted on 15 May 2026
-1 points (40.0% liked)

cybersecurity

6149 readers
76 users here now

An umbrella community for all things cybersecurity / infosec. News, research, questions, are all welcome!

Community Rules

Enjoy!

founded 2 years ago
MODERATORS
 

First big one is app/activitypub/routes.py where a signature verification fail fall back code fetches the remote object without any cryptographic verification, then just trusts it allowing an attacker to send unsigned Create activities and have them processed as legitimate.

When a remote ActivityPub server sends a Create or Update activity to piefed's shared inbox, the verification logic at routes.py attempts two cryptographic checks. It starts with checking HTTP signature, then a Linked Data signature, and if both fail, instead of rejecting the activity, the code checks whether the inner object is a JSON dict with an id field, and if so, reduces it to just a URI string and lets it proceed with Actor found status. Later, process_inbox_request sees the object is a bare string and calls verify_object_from_source(), which fetches the object from the remote URL performing no cryptographic verification at all. The only check it makes is that the object's domain matches the actor's domain, which the attacker controls!

So, if an attacker stands up a server at evil.com and sends an unsigned Create activity to the victim's inbox with actor: "https://evil.com/user/alice" and object: {"id": "https://evil.com/post/1", "type": "Note", ...}. Both signature checks fail because the attacker never possessed any valid key. But since the object is a dict with an id, it gets reduced to just "https://evil.com/post/1" and the activity passes through. Later, verify_object_from_source fetches https://evil.com/post/1 which the attacker's server responds to with whatever JSON payload they want like spam, phishing links, hate speech, CSAM and processes it as a legitimate federated post attributed to the attacker's actor. The attacker can do this repeatedly from any domain they control, impersonating any actor, with no key infrastructure whatsoever.

This completely bypasses the identity model of the fediverse. Any domain can inject content into the server's database that appears to come from a legitimate federated user, bypassing all moderation at the source-server level. The attacker needs no key and no prior presence on the network, or even any relationship with the target instance. They just need the ability to send an HTTP POST to the inbox endpoint.

Another second critical vulnerability is a systemic SSRF across the entire outbound HTTP layer.

The get_request() at utils.py is the single HTTP client function used by every federation code path across activitypub/actor.py, activitypub/util.py, and activitypub/signature.py. It receives a URL and calls httpx_client.get(uri, follow_redirects=True) with zero validation of where that URL points. The URLs come from untrusted remote ActivityPub JSON objects such as actor profiles, post objects, webfinger responses, community metadata, image references, and nothing checks whether the hostname resolves to a private, loopback, link-local, or some cloud-metadata IP address.

The most direct entry point is fetch_actor_from_webfinger() at actor.py. When a user searches for a remote actor like @attacker@evil.com, piefed calls get_request(f"https://evil.com/.well-known/webfinger"). The attacker's server responds with a webfinger JSON that returns a self link pointing to http://169.254.169.254/latest/meta-data/iam/security-credentials/. Piefed follows that link at line 211, and the response body, which is say cloud credentials, flows into the actor creation pipeline and gets logged and stored in the database. The same pattern repeats everywhere with verify_object_from_source() fetching object URIs from untrusted actors, 1refresh_user_profile_task()downloading avatar/header images from URLs embedded in remote actor data,save_og_image()` downloading OpenGraph images from any URL a user posts, instance polling fetching {protocol}://{instance.domain} for every federated instance.

Since httpx.get() with follow_redirects=True will follow HTTP redirects, an attacker can even serve a legitimate-looking URL like https://evil.com/avatar.png that 302-redirects to http://127.0.0.1:6379/ or internal admin panels. There is no DNS rebinding protection, no IP allowlist, no protocol restriction to HTTPS, and no redirect chain inspection.

What this means is that an attacker can register a domain running a malicious ActivityPub server, and send a Follow activity to the victim server. The victim fetches the attacker's actor profile, which contains icon.url = "http://127.0.0.1:6379/". The application process connects to its own local Redis instance, which returns a plaintext error like NOAUTH Authentication required. That response is written to disk as the actor's avatar image, and the error message confirms Redis is present and unauthenticated, and it very much is unauthenticated. The attacker then sends a second activity with an icon.url pointing to http://127.0.0.1:5432/, probing PostgreSQL, or http://127.0.0.1:8080/admin/ to fingerprint internal dashboards. Each response is persisted to the filesystem where the attacker can eventually retrieve it, mapping out the internal network one federated request at a time.

The implications are that the federation protocol itself becomes a port-scanning and data-exfiltration channel. Every remote ActivityPub server the instance talks to can force it to make arbitrary HTTP requests to any address reachable from the piefed host, with the response data potentially persisted to disk or logged. Combined with the unsigned activity processing, an attacker doesn't even need a real server, they can just POST to /inbox.

And these are just a couple of egregious examples, there are plenty of terrible things like hardcoded default SECRET_KEY fallback used to forge sessions and JWT password reset tokens for any account, command injection vulnerabilities with os.system() calls, and so on.

OC by @yogthos@lemmy.ml

you are viewing a single comment's thread
view the rest of the comments
[–] meowmeow@quokk.au 2 points 1 day ago

While not trying to defend PieFed, you could say other Fediverse software is run by people who favor their accepted form of fascism and authoritarianism.