YesWiki 4.6.7 wave — secondary-handler ACL drift, federation signature binding, deferred identifier SQLi, and GET-mutation CSRF¶
Source: GitHub Security Advisory wave published 2026-10-02 12:31Z (YesWiki < 4.6.7, 36 GHSAs; CVE-2026-104438–104472). Related existing pages: Sept 18 semantic-MediaWiki unauth API page, Sept 21 management-plane flat-authz drift page, Sept 19 WordPress alternate-surface page.
One rule covers the majority of this wave: the ACL is written where the page renders, not where the page data is read or written. YesWiki ships dozens of sibling handlers over the same storage — attachment download, RSS actions, the comments API, the triples API, Bazar entry creation, tag listings, image actions — and most of them never call the read/write ACL check. On any wiki/CMS with per-page ACLs, build the handler inventory first; the primary render path passing its ACL tests tells you nothing.
What changed (promoted legs)¶
| Advisory | Handler | Boundary | Operator value |
|---|---|---|---|
| GHSA-m45w-rvq4-f22g / CVE-2026-104472 (7.5) | Attachment download handler | Unauthenticated: known page tag + file param returns attachments from read-ACL-restricted pages | Attachments are a second read path with no ACL call. Enumerate ?download/ style handlers with guessed tag+filename pairs against restricted pages |
| GHSA-h2q6-cgj7-p65g / CVE-2026-104449 (6.5) | Bazar entry creation | Unauthenticated write: crafted entry with id_fiche matching an existing page overwrites its body, write-ACL bypassed | Creation flows that accept a caller-chosen target identifier are write primitives on existing rows. Try to "create" over something you don't own |
| GHSA-mf95-w988-564j / CVE-2026-104450 (6.5) | pointimage action (tools/attach) | Unauthenticated POST saves content to an attacker-chosen page with write-ACL checks bypassed | Third write path around the same pages table — count the routes that can save, not the bugs |
| GHSA-gr78-chgv-6fgg / CVE-2026-104443 (8.1) | Triples delete API | Empty-filter scope bypass: any authenticated user deletes/forges arbitrary semantic triples regardless of ownership — deleting the admins-group membership triple empties the admin group | Delete/maintenance endpoints where an empty filter means "everything" instead of "nothing". Also a deliberate lockout tool — prove with your own disposable group only |
| GHSA-gch9-x4v5-hp56 / CVE-2026-104444 (7.1) | Comments API editComment | Low-privilege authenticated users overwrite arbitrary pages/comments by supplying their own page as the pagetag field while targeting a victim tag — per-page write ACL bypassed, content replaced and pages reparented | Authorization checked on the wrong object of a two-object request (your own pagetag passes the check while the victim tag is the actual write target). Whenever a request carries two identifiers, confirm which one the permission check resolves — the Sept 21 Blazar "authorizes-under-wrong-param" twin |
| GHSA-59xh-vh54-x5hf / CVE-2026-104467 (8.1 critical) | ApiService::isAuthorized() | Unauthenticated calls to admin-only API routes (api/ci/update_config, api/archives list/download/delete) when public API mode is enabled | A product feature flag (public API) silently widens the route ceiling to admin scope. Toggle-state-dependent route families must be re-authorized-matrixed in each state. Config overwrite + backup archive read/delete from one unauthenticated call |
| GHSA-x8xj-595c-jcc3 / CVE-2026-104455 (5.3) | recentchangesrssplus action | Unauthenticated xml method returns 500-char excerpts of every latest page including read-restricted drafts/notes | RSS/feed actions are read paths that skip read-ACL filtering. Request every action's alternate output method (xml, rss, json) on pages whose HTML view correctly denies you |
| GHSA-fm39-cmv6-r4rj / CVE-2026-104438 | listpagestag / includepages (tags tool) | Page listings with no read-ACL filtering, unauthenticated | Listing actions leak restricted page titles/sets — the tag graph is a disclosure map for what exists behind ACLs |
| GHSA-px48-25j6-h73c / CVE-2026-104445 (8.2) | ActivityPub inbox | HTTP signature verified but signer never bound to the activity actor — any valid keypair can send signed Delete/Update referencing a mirrored entry's sourceUrl to delete/overwrite other actors' federated content | Federation signature-binding axis: signature verified ✓ ≠ signer == actor. On any ActivityPub/inbox handler: sign an activity with your own key, point actor/sourceUrl at a victim entry, and see what accepts it. Same invariant applies to webhook signing (compare: n8n trigger-HMAC class on the Oct 1 page) |
| GHSA-ghw3-mg2w-7jg2 / CVE-2026-104464 (8.6) | Bazar abonnements sync action | Unauthenticated SSRF via unvalidated actor URL, and the fetched response is stored as a readable Bazar entry — full read-back; attacker-controlled outbox first/next links chain further server-side fetches | Two durable SSRF upgrades in one bug: (1) read-back by design (fetched content persisted as user-visible content, not blind), (2) link-chained multi-hop crawl — your callback returns a JSON-LD outbox whose next points at 169.254.169.254 and the crawler walks there itself. Test federation/sync fetchers for response persistence and pagination-following, not just first-hop reachability |
| GHSA-jf5x-83r6-59f3 / CVE-2026-104442 (5.8) | render.php content param → syndication action | Unauthenticated SSRF, fetched feed content rendered back into the page, and feed enclosures downloaded into the web-accessible files directory | SSRF → arbitrary-file-write-into-webroot via enclosure handling. When a fetcher "helpfully" localizes remote assets, the download leg inherits the SSRF destination |
| GHSA-pg4j-r96p-6rg4 / CVE-2026-104459 (6.5) | WebfingerService | Unauthenticated HTTPS requests via actor_handle with a numeric host and port (dotted-decimal/integer IP form) | Alternate address encodings defeat string denylists (http://2130706433/ style). Include decimal/octal/hex host spellings in every SSRF battery |
| GHSA-992m-5rj6-qxj2 / CVE-2026-104440 (5.3) | /api/entries/bazarlist idtypeannonce | Blind SSRF because isValidURL() always returns true | When you can read source (or error-text gives it away), grep the validator — a function that unconditionally returns true is a documented bypass. Black-box equivalent: the parameter accepts everything you expected to be blocked |
| GHSA-m352-5gh7-99x6 / CVE-2026-104456 (7.6) | AclService::updateRequestWithACL | Second-order SQLi: self-register a username containing a double-quote payload; later ACL-filtered listings concatenate the stored username unescaped into a LIKE clause → read DB contents, bypass read ACLs | Identifier-as-injection-vector, self-seeded: register/store the payload in an identity field nobody escapes, then trigger the consumer query (listings, exports, searches). The write is trivially legal; the read is deferred |
| GHSA-3q4q-74cq-96xq / CVE-2026-104460 (7.5) | {{newtextsearch}} action | Blind SQLi: Bazar list option ids concatenated into REGEXP/LIKE clauses; anonymous attackers plant the malicious option id in an anonymously editable Bazar list, then use search requests as a boolean oracle to read arbitrary tables incl. password hashes | Deferred SQLi with a planted value: the injection point reads config someone else can edit anonymously. Map every "option/config" store that search/list code later interpolates |
| GHSA-f8w7-2q27-5p28 / CVE-2026-104457 (8.6) | Bazar filtertags action | SQLi via trailing-backslash token that breaks quote parity under MySQL backslash escaping → five-column UNION subquery reading arbitrary data | The escape-the-escape class: input \"-style handling differs between the app's quote-wrapping and MySQL's string parser — a trailing \ swallows the closing quote. Always test trailing backslashes on every quote-wrapped SQL parameter, and match UNION column arity from error/behavior probing |
| GHSA-mvpf-2445-p988 / CVE-2026-104462 (7.5) | Bazar nuagetag action | Unescaped tags attribute into raw IN (...) clause; page-write access = unauthenticated on default installs | Default-install privilege floor: "authenticated editor" primitives are unauthenticated out of the box on this CMS. Baseline what a fresh install lets an anonymous visitor do before testing authenticated paths |
| GHSA-6qxf-8854-q5c5 / CVE-2026-104448 (8.1) | ajaxdeletepage | Permanent page delete on GET carrying jsonp_callback, no CSRF token | Destructive-GET sweep: GET every admin/UI handler with a mutating-looking name; a JSONP-era callback param that re-enables the handler is the giveaway. Revision-restore (CVE-2026-104451), filemanager attachment delete (CVE-2026-104452), admintag delete (CVE-2026-104453), autoupdate package delete (CVE-2026-104447) are the same class across five handlers — a whole product's worth of unprotected GET mutations |
| GHSA-g4m2-8g7g-xw8c / CVE-2026-104471 (7.2) | Bazar CSV import preview | Authenticated admin: CSV whose file/image field is a remote URL → server writes the fetched remote file into web-accessible files/ | "Preview" fetches the remote value before import finalizes — an import-preview leg is an SSRF+write even when the upload path itself is restricted. Test preview with remote URLs, not just local files |
| GHSA-c9hw-c2mv-jj5c / CVE-2026-104469 (6.8) | Login | Session fixation: no session-id regeneration on login; plant a pre-auth YesWiki-* cookie, victim logs in, you ride the known id | Standard fixation re-check on every CMS: plant → authenticate victim in lab → does the session id survive login? |
| GHSA-6c43-xgw2-65px / CVE-2026-104468 (4.8) | Password reset | Reset tokens lack expiry timestamps — unused links work forever from old mailboxes/logs/backups | Password-reset tokens: check expiry and single-use. An old leaked reset URL that still works is a persistent ATO foothold; sweep historic mail archives in phishing-scope engagements |
| GHSA-c595-8pv9-m3vm / CVE-2026-104446 (6.5) | Contact mail AJAX handler | Unauthenticated email relay through the wiki's SMTP (fields absent from the AJAX shape skip validation) | AJAX variants of form handlers validate a different field set than the form path — unauthenticated send-mail relay. POST the AJAX shape, not just the form |
| GHSA-c49r-h57h-8wfx / CVE-2026-104461 (5.4) | Bazar FileField | Upload validated by extension only; the HTML-purifier file-clean step is never called → SVG stored verbatim and served inline → stored XSS | Extension-check-only + skipped sanitizer = the two-defect pair that makes SVG upload work. Try SVG-with-script on every "document" upload field, then confirm the serving context renders it inline |
Durable axes¶
- Per-page ACL is a property of the render path only — enumerate sibling handlers over the same storage. This single CMS shipped unauthenticated reads (attachment download, RSS excerpts, tag listings, triples reads) and unauthenticated/low-priv writes (entry-creation-by-existing-id, pointimage save, comments-API page targeting) all around the same page ACL. On any wiki/CMS/knowledge-base target: list every action/API/output-format that touches page content, then replay both ACL axes (read restricted, write not-yours) through each handler. The primary view correctly denying you is the control, not the result.
- Feature flags change the route ceiling. Public-API mode turned admin routes (
update_config, archive list/download/delete) into unauthenticated surface. Rebuild the authorization matrix per feature-flag state; toggle flags you can influence via config write or trial installs and re-probe the API family. - Empty/default filters on bulk APIs are apply-all by default. An empty filter on a delete endpoint = site-wide destruction. Always send
{}/ omit the filter object; expect a validation error, and report when you get a mutation. Pair with the delete-then-repopulate reality (deleting your own lab group's membership triple as proof). - Federation/webhook invariants: signature-verified must bind signer to actor. Verify the identity inside the payload is the identity that holds the key. Test cross-actor Delete/Update with your own valid keypair on ActivityPub inboxes; test cross-tenant replay on every HMAC'd webhook receiver.
- Deferred identifier SQLi: the injection write and read are different requests by different code. Your username, a planted Bazar option id, a stored tag token — anything persisted unescaped and later interpolated into a query. Sweep: store quote/backslash variants in every identity/config field you can set (including anonymously editable config), then trigger every listing, search, feed, and export consumer.
- MySQL backslash quote-parity breakout. A trailing
\in a value the app merely wraps in quotes swallows the closing quote under MySQL's default escaping and reopens the string. Include\",\and double-encoded spellings in every quote-wrapped parameter battery; recover column arity for UNION via error/boolean probing. - Destructive GET is a product-wide pattern, not a single bug. Five separate handlers in one product deleted pages, attachments, tags, packages, and revisions on unauthenticated-for-CSRF GET. A GET sweep of mutating handlers with disposable state enumerates the whole class in an afternoon.
- Fetchers inherit their destination: sync/preview/syndication legs read back (content persisted as viewable entries), crawl on (attacker-controlled
nextlinks), and localize (enclosures downloaded into webroot). Each leg upgrades blind SSRF into read, multi-hop, or file-write — test all three per fetcher.
Validation boundaries¶
Lab YesWiki < 4.6.7 with disposable pages, two synthetic accounts, marker attachments, and synthetic Bazar lists only. SSRF proofs use owned callbacks and self-owned multi-hop JSON-LD responders; never target cloud metadata or third-party internal hosts. SQLi proofs read marker rows and stop — no real user-table dumps in reports (hash extraction described, not performed, on shared instances). ActivityPub proofs use your own keypairs and mirrored synthetic entries; never delete or overwrite real federated content. GET-mutation proofs fire only against your own disposable pages/packages. Fixation/reset proofs use lab victim sessions you control.
October 4 18:3xZ follow-up: the valeur.php fetch-and-render pair — one handler, SSRF leg + stored-XSS leg¶
Two advisories for the same Bazar valeur action (tools/bazar/actions/valeur.php) landed split across waves — the SSRF leg published Oct 2 (surfaced in the updated feed Oct 4), the XSS leg Oct 4:
- GHSA-32r4-8mw9-77h4 / CVE-2026-104470 (medium) — page-editor
urlparameter makes the server fetch arbitrary URLs (loopback/internal probing) and injects the fetched remote HTML unescaped into the rendered page. - GHSA-4jc3-v5mf-cppg / CVE-2026-105224 (medium) — same handler pointed at a controlled server returning
BAZ_fiche_titremarkup with animg onerrorexecutes script in every viewer's browser — editor-privilege foothold becomes stored XSS against all readers.
Durable axes: (1) a fetch-and-render action is two bugs wearing one coat — probe it once for internal-URL acceptance (SSRF) and once for remote-HTML execution (viewer-side XSS); the impact split (editor-only authority vs all-viewer execution) makes the XSS leg the escalation path. (2) This extends durable axis 8 (fetchers inherit their destination) with a fourth leg: render — the fetched bytes are emitted into the page DOM, not just stored or followed. When you find any "embed/fetch/preview a URL" field, the full battery is read-back / crawl-on / localize / render. (3) Same-handler advisories split across days: when you fold one leg of a product's fetch handler, grep the advisory feed for the sibling CVE/param before closing the page.
Tracked from this wave without publication¶
- YesWiki XSS/DoS singles: wakka.php markdown-image-quote stored XSS (CVE-2026-104466), reflected XSS via
field/incomingurl/id/file/tags/templateparams (CVE-2026-104465/104473), O(n²) bracket-body formatter DoS (CVE-2026-104454), user enumeration via differing LostPassword responses (CVE-2026-104439) — generic classes already canonical on existing pages. - Same-wave Apache Thrift < 0.25.0 seventeen-GHSA language-binding pack (CVE-2026-82458/86535/86536/86537/90440/91137/94633/94636/94645/94646/94651/96288/96292/97876/85086/93926 + NodeJS TJSONProtocol prototype pollution) — parser memory-safety/DoS in non-primary bindings, tracked per parser precedent; recon note kept: exposed Thrift binary-protocol RPC ports (no HTTP) fingerprint via zero-length/oversized-field probes, and Node/Dart/Python binding fixes are per-language — fingerprint the binding, not just "Thrift".
- Zcash Zebra node eighteen-GHSA pack (consensus divergence, peer-discarded provenance, mempool-limit bypass, block-sync DoS) — consensus/memory-safety class, no reusable operator workflow at advisory detail level; revisit if a consensus-divergence advisory ships with protocol-level exploit detail.
- SiYuan publish-reader trio promoted as a fold (see July 10 File Browser/SiYuan page); Ghost eight-pack folded on the Aug 4 Ghost page.
- HospitalManagementSystem ID-parameter SQLi (thin detail), GRUB Secure Boot lockdown bypass (local/boot class), unnamed protocol-gateway
account_namestack overflow (detail-free), itsourcecode singles — processed class.