Changelog
[2.2.0] 2026-08-17 Security (3) · Changed (1)
Security release. The prerender fix is the important one: the generated prerender.php is a file you deploy to production, and the previous template interpolated build-time config into PHP source unescaped. Anyone shipping preRender should upgrade and regenerate.
Security
- Remote code execution in the generated
prerender.php(src/prerender.ts).preRender.url,preRender.delayandpreRender.cachewere pasted into the PHP template as raw source text, so a value containing a quote closed the string literal and everything after it was executed as PHP on the deployed server. The values reach the template fromvite.config.tsand, in the common setup, from an env var (PRERENDER_URL) — i.e. from a CI variable or an.envfile, not necessarily from the person reading the config. Each value is now encoded for the position it lands in: strings viavar_export-style quoting,delay/cachecoerced to integers.CURLOPT_SSL_VERIFYPEER/CURLOPT_SSL_VERIFYHOSTare now enabled in the same file — the template previously disabled TLS verification outright, so the prerendered HTML served to crawlers could be substituted by anyone on the path between the server and the prerender service. - Newline injection into
.htaccess(src/generateHtaccess.ts). Thecrawlersoption was interpolated into aRewriteCondline verbatim; a value containing a newline could terminate the condition and append arbitrary Apache directives to the deployed.htaccess. Newlines and.htaccessmetacharacters are now stripped from the value, and an empty/whitespace-only result falls back toDEFAULT_CRAWLERSrather than emitting a condition that matches everything. - Path traversal in
compressBuild(src/compressBuild.ts). The zip file name came from config and was joined onto the build directory unchecked, so../../deploy.zipwrote outsideoutDir. The name is now reduced to itspath.basename, containing the write to the build directory.
Changed
- Env values substituted into
index.htmlare now HTML-escaped (src/resolve-env-in-htm.ts).{{ VITE_X }}placeholders were replaced with the raw env value, so an env var carrying markup (</title><script>…) became live HTML in the built page — a stored-XSS path for anyone who can set a build-time variable. Values are now escaped (&,<,>,",') before substitution, and the replacement is literal: a$&or$1inside a value is no longer interpreted as a regex replacement pattern. Behaviour note: if you were intentionally injecting markup through an env placeholder, it now renders as text. Emit that markup fromindex.htmlitself instead.
[2.1.4] 2026-05-26 Added (7) · Fixed (4) · Changed (1)
Added
- Marketing-style README. Drop-in
vite.config.tsexamples, an option-by-option reference table, the env-file resolution chain, a full options reference, a Caveats section, and worked examples for minimal SPA setup, CDN base URL via env, Apache.htaccess+ prerender deploy, multi-stage builds, and env-only mode. llms.txt/llms-full.txt. AI-discoverable index and concatenated reference matching the@mongez/atomshape so the docs aggregator picks them up.skills/folder. Reference cards for tool-assisted development —README(index),overview(pitch + mental model), per-feature cards (env-loading,env-in-html,tsconfig-aliases,auto-open-browser,production-base-url,build-zip,htaccess,prerender), andrecipes(cross-feature compositions and workedvite.config.tsfiles).- Vitest test suite. 70 passing assertions across ten test files covering the plugin factory shape, default options table, in-HTML env interpolation, the dev-server browser auto-open helper, tsconfig path mirroring,
.env.<env>file resolution per command, theproductionEnvNameoverride, production base URL derivation, optimizeDeps installation, the prerender PHP template, an integration test that drives the fullconfig()hook with chdir’d fixture directories, and regression guards for the four bugs fixed below. - CI workflow. GitHub Actions matrix matching the rest of the
@mongez/*family: Node 18 / 20 / 22 on Ubuntu, plus Node 20 on Windows. - Vitest config. Self-detecting sibling-alias pattern — when run inside the monorepo it resolves
@mongez/events,@mongez/reinforcements, and@mongez/dotenvto the sibling sources for live cross-package edits; in CI / standalone checkouts those aliases are dropped and resolution falls back tonode_modules. package.jsonpolish. Expandeddescription(now lists every feature, not just “manage development and build process”),sideEffects: falsefor tree-shaking by downstream consumers (note: the package is itself a Vite plugin so this is mostly informational), additionalkeywordsfor npm searchability (vite-plugin,spa,single-page-application,htaccess,prerender, etc.),test/test:watchscripts wired to vitest, andvite+vitestadded underdevDependenciesso the package canyarn installstandalone.
Fixed
Each was reproduced as a .skip() test in src/__tests__/known-bugs.test.ts; the tests have been unskipped and now assert the fix:
src/generateHtaccess.ts:1—import { MongezViteOptions } from ".types"(missing slash). Survived runtime because the import is type-only and esbuild elides it, buttsc --noEmitagainst the source would fail. Fixed: import now readsfrom "./types".src/compressBuild.tsscheduled the zip job insetTimeout(..., 1000)despitewriteBundlebeing declaredsequential: true. Vite considered the handler done before the zip was created — consumers runningvite build && upload-dist.shcould upload an incomplete artifact. Fixed: dropped thesetTimeoutwrapper. The function now awaits the archive pipeline directly, so by the timecompressBuild()resolves the zip is on disk. Backward-compatible: Vite’swriteBundlehook supports async returns natively.preRender.urlhad no default and no runtime guard — passingpreRender: {}interpolated the literal stringundefinedinto both the rewrite rule and the generatedprerender.php. Fixed:generateHtaccess()now throws a descriptive build-time error ifpreRenderis truthy butpreRender.urlis missing. The throwing approach (rather than tightening the TypeScript type) catches the bug at runtime for JS consumers too.- Legacy README naming:
envPrefix/envSuffix. Older revisions documented option keys that the runtime never read; the source readshtmlEnvPrefix/htmlEnvSuffix. Fixed: the README andskills/env-in-html.mduse the correct names. A regression-guard test asserts the doc surfaces stay in sync.
Changed
viteis declared as apeerDependency(>=5.0.0) and now also as adevDependency(^5.0.0) so the test suite can resolve it without a containing app providing it.
Tests
70 passed | 0 skipped