Page MenuHomePhabricator
Paste P96452

vue-router-vuls.md
ActivePublic

Authored by jsn.sherman on Mon, Sep 14, 7:46 PM.
Project Tags
None
Referenced Files
F102933639: vue-router-vuls.md
Mon, Sep 14, 7:46 PM
Subscribers
None
# vue-router (core bundling) Security Review
**Target:** `resources/lib/vue-router/` + `resources/Resources.php:611` (module `vue-router`), mediawiki/core @ HEAD (`b9931185ea7`, master)
**Merge under review:** `0054ca7dbd2` "Add vue-router to core for use by extensions/skins" (Bug: T290916, T436156)
**Reviewer:** Claude (retroactive audit, requested post-merge)
**Date:** 2026-09-14
## Methodology / Scope
Threat model: an ordinary anonymous or registered Wikimedia user, reachable only through whatever public ingress a MediaWiki extension or skin exposes on top of this library. vue-router itself ships no server component, so the question is entirely about what core's registration does and what (if anything) currently feeds it attacker-controlled data. Audited at core's current HEAD rather than pinned to the merge commit, per the engineer's direction, since production risk lives wherever the code is now.
Files reviewed in detail:
- `resources/Resources.php` (the `vue-router` and `vue` RL module definitions, lines ~580-635)
- `resources/lib/vue-router/vue-router.global.js` (vendored, 3961 lines) and `vue-router.global.prod.js`
- `resources/lib/foreign-resources.cdx.json` / `.yaml` (provenance entry, confirms `vue-router@4.5.1`)
- Full-tree grep for any core, extension, or skin code that calls `createRouter`, `createWebHistory`, `createMemoryHistory`, `createWebHashHistory`, or otherwise depends on the `vue-router` RL module
## Summary
No findings. Nothing in mediawiki/core currently invokes vue-router; the merge added only the vendored library and its ResourceLoader registration, with zero consuming call sites.
## Findings
None. There is no attacker-reachable path today: the library is registered but unused, so there is no public byte that reaches any vue-router code path via any ingress.
## Not currently exploitable
None identified as code-level bugs — see "Reviewed without finding" below for what was checked and ruled out.
## Reviewed without finding
- **RL module wiring** (`resources/Resources.php:611-635`). The `vue-router` module is a `packageFiles` definition that `file_get_contents()`s a static, repo-vendored file and string-concatenates a `require('vue')` prefix and `module.exports` suffix around it. All inputs to the concatenation are static file paths selected by `$wgVueDevelopmentMode`/RL debug context, not attacker data. This is a byte-for-byte mirror of the pre-existing `vue` module registration immediately above it in the same file — no novel pattern, no injection surface.
- **Dev vs. prod build selection.** Same debug-mode gate (`context->getDebug()`) as every other RL library module (`vue`, `jquery`, etc.). Serving the unminified build under `?debug=true` is documented, existing ResourceLoader behavior, not something this merge introduced.
- **Consuming call sites.** Grepped mediawiki/core (including the empty `extensions/`/`skins/` placeholders in this checkout) for `createRouter`, `createWebHistory`, `createMemoryHistory`, `createWebHashHistory`, and any `extension.json`/`skin.json` declaring `vue-router` as a dependency. None found. Nothing in core parses a URL, route param, or query string into this library today.
- **Vendored library source** (`vue-router.global.js`). Grepped for `eval(`, `new Function(`, `innerHTML`, `document.write`, `__proto__`/`constructor.prototype` assignment patterns — none present. Route matching is vue-router's own regex-based matcher (not the old `path-to-regexp` lineage that had prior prototype-pollution CVEs in other ecosystems).
- **Known-vulnerability check.** No CVE/GHSA advisory found against `vue-router@4.5.1` itself (checked via web search against GitHub Advisory Database / OSV / OpenCVE, 2026-09-14). The one adjacent advisory found, GHSA-mm7m-92g8-7m47, is a Nuxt-specific `routeRules` middleware bypass caused by Nuxt's own route-rule matcher disagreeing with vue-router's case-insensitive-by-default matching — it requires a second, Nuxt-side matcher that MediaWiki has no equivalent of, so it doesn't transfer here as-is. Recorded below as a forward-looking caution, not a finding, since it's the shape of bug this bundling could reproduce once something builds gated routes on top of it.
- **Provenance record** (`foreign-resources.cdx.json`/`.yaml`). Matches the vendored version (`4.5.1`) and license (MIT); consistent, no discrepancy.
## Recommendations beyond the findings
- **This is a pre-emptive audit, not a clean bill of health for future use.** The risk here is entirely deferred to whichever extension or skin first wires a `router = createRouter(...)` against MediaWiki's URL surface. Re-run this audit (or a scoped version of it) against the *first* real consumer, once one exists — the interesting questions (does a route param get rendered unescaped into a `<router-view>`, does anything build a client-side "redirect" from `location.search`, is a route guard used as if it were an authorization check) can't be answered until there's a call site to point at.
- **Flag the matcher defaults for whoever adopts this first.** vue-router 4.5.1 defaults to `sensitive: false, strict: false` (`vue-router.global.js:990-991,1420`) — case-insensitive, trailing-slash-tolerant route matching. That's the exact defaults mismatch that produced GHSA-mm7m-92g8-7m47 in Nuxt. If a future MediaWiki extension ever gates a route behind a permission check keyed on the matched path string, it should either set `sensitive: true` or do the permission check server-side (PHP), not by string-comparing the client route.
- **Client-side route guards are not an authorization boundary.** Worth stating explicitly in whatever developer-facing docs come with this module (mediawiki.org VueRouter docs, if any get written): any `beforeEach`/`meta.requiresAuth`-style guard is client-side and fully attacker-controlled; real permission checks belong in the PHP API/REST layer the SPA talks to, per MediaWiki's existing convention for every other client-rendered UI.