# Remote attacker can impersonate Social users via ActivityPub API

Nextcloud Social's ActivityPub shared inbox trusted a spoofed actor id from a foreign keyId URL, letting an unauthenticated attacker post as any local user.

- Payout: hidden
- Severity: high
- Program: Nextcloud
- Found by: tomk
- Disclosed: 2019-02-01
- Write-up quality: 8/10
- Original: https://hackerone.com/reports/461308
- Library page: https://bugbountylibrary.com/r/h1%3A461308
- Tags: area:web domain:web impact:integrity kind:bounty platform:hackerone sev:high tech:php technique:source-review vuln:access-control vuln:auth-bypass vuln:misconfiguration vuln:signature-replay

**Target:** ActivityPub shared inbox endpoint (/apps/social/inbox) signature verification
**Root cause:** When fetching an unknown remote actor via the keyId URL, the returned JSON 'id' field is not validated to share the keyId's origin, so an attacker hosts their own pubkey under a victim-origin id. Signature verification then accepts any key whose actor id origin matches the ActivityPub item's origin.
**Steps:**
1. Generate an RSA keypair and sign `(request-target): post /nextcloud/index.php/apps/social/inbox` with SHA256 (gen_request.php).
2. Fetch a victim profile: `curl -H "Accept: application/ld+json" https://victim/nextcloud/index.php/apps/social/@testuser2`.
3. Edit the JSON: set `id` to `https://victim/nextcloud/index.php/apps/social/@mallory` and replace publicKeyPem with the attacker key; host at `https://attacker/mallory.json`.
4. Prime the cache: `curl -H 'Signature: keyId="https://attacker/mallory.json",headers="(request-target)",signature="x"' -X POST -d "" https://victim/nextcloud/index.php/apps/social/inbox` — fails but stores actor in oc_social_cache_actors with victim-origin id.
5. POST a Create/Note to the shared inbox with `keyId="https://victim/.../@mallory"` and the precomputed signature, actor set to testuser2.
6. Note appears in followers' Home timelines as testuser2.
**How found:** Code review of the shared inbox signature check: noticed the downloaded actor's 'id' origin was never compared to the keyId URL origin, and that signature verification only requires the key's actor origin to match the item origin.
**Exploitation:** Attacker needs only an HTTPS host for the spoofed actor JSON. First request poisons the actor cache with an attacker-controlled pubkey bound to a victim-origin id; second request signs a Create-Note with that key, impersonating any local user to their followers.
**Escalation:** Beyond posting: phishing/malware links, spam/DoS, possibly content deletion (untested).
**Insight:** In federated protocols, always bind a fetched actor's self-declared id to the URL it was fetched from; otherwise cache-priming with a foreign-origin id lets you inject your own key for a victim's origin.

