Skip to content

[SECURITY] Rebuild theme JS bundles so the merged fixes ship#1353

Merged
linawolf merged 1 commit into
mainfrom
task/rebuild-theme-assets-security
Jul 26, 2026
Merged

[SECURITY] Rebuild theme JS bundles so the merged fixes ship#1353
linawolf merged 1 commit into
mainfrom
task/rebuild-theme-assets-security

Conversation

@CybotTM

@CybotTM CybotTM commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

The three advisory fixes are merged and tagged in 0.40.0, but the published assets do not contain them. assets/js/search.js and resources/public/js/theme.min.js are committed build artifacts and were never rebuilt. Re-rendering a manual does not help — the theme version is pinned in the asset URL, so a re-render fetches the same vulnerable file.

This is why https://docs.typo3.org/m/typo3/tutorial-getting-started/13.4/en-us/?q=%3Cimg%20src=x%20onerror=alert(document.domain)%3E still fires after a fresh render.

Evidence

The CDN serves exactly the artifact committed at tag 0.40.0:

CDN 0.40.0/js/theme.min.js       md5 67ee48dc0483752ddbcbe68b64639efb   239212 bytes
repo @ 0.40.0, theme.min.js      md5 67ee48dc0483752ddbcbe68b64639efb   239212 bytes

That artifact was last changed in f795385 on 14 July — eleven days before ab24ff7, db881fd and a22f55b.

Markers that survive minification, old versus rebuilt:

marker origin search.js theme.min.js
MARK sanitizeHtml.js, a22f55b 0 → 1 0 → 1
' attrEscape(), ab24ff7 0 → 2
https: safeUrl() allowlist, ab24ff7 3 → 5

Executed, not just read: loading each bundle in jsdom against a real rendered page and opening the info modal with data-details="<img src=x onerror=…>"

  • deployed bundle: <img src="x" onerror="window.__xss = true"> lands in the DOM as a live element, [onerror] present
  • rebuilt bundle: rendered as inert text, no img, no [onerror]

The build is reproducible — two consecutive npm run build runs produced identical hashes, and the committed files match both.

Scope

Only the two JS artifacts. npm run build also regenerates resources/public/css/theme.css and the FontAwesome woff2 files, which have drifted since #1333; that drift is older than this incident and is reverted here so the security release carries nothing else. It needs its own PR.

Verification

npm test                     5 files, 23 tests passed

No source file changes, so the diff is the artifacts only.

After merge

0.40.1 needs to be tagged and the manuals re-rendered — the version is part of the asset URL, so the release is what actually ships the fix.

How this got through

There is no CI job that builds the assets or compares them to the committed ones. #1265 adds exactly that check (.github/workflows/check-built-assets.yaml) and has been open since 24 May with all checks green. It triggers on pull_request only, so as written it would not have caught these three commits either — advisory merges land as direct pushes to main, without a PR. Worth merging with a push trigger on main added.

assets/js/search.js and resources/public/js/theme.min.js are committed
build artifacts. Neither was rebuilt after ab24ff7, db881fd and
a22f55b, so the published 0.40.0 assets still carry the vulnerable
code and re-rendering a manual cannot help: the theme version is pinned
in the asset URL.

The bundle served from
cdn.typo3.com/typo3documentation/theme/typo3-docs-theme/0.40.0/js/theme.min.js
is byte-identical to the artifact committed at tag 0.40.0, whose last
change predates the three fixes by eleven days.

Rebuild both artifacts from the current sources. No source change.

Signed-off-by: Sebastian Mendel <github@sebastianmendel.de>
@linawolf
linawolf merged commit d2b69eb into main Jul 26, 2026
10 checks passed
@linawolf
linawolf deleted the task/rebuild-theme-assets-security branch July 26, 2026 07:46
CybotTM added a commit to CybotTM/render-guides that referenced this pull request Jul 26, 2026
…entation#1354)

The generated files in `packages/typo3-docs-theme/resources/public/` are
older than the sources they are built from. Rebuilding tag `0.40.1` with
`npm ci && npm run build` on Node 24.16.0 (`.nvmrc`) produces a
different `theme.min.js`, a different `theme.css` and four different
font files; `bootstrap.min.js` comes out byte-identical.

## The info modal of the `:php:` text roles is broken in 0.40.1

`theme.min.js` was last built in TYPO3-Documentation#1353. TYPO3-Documentation#1345 then changed both
`assets/js/code-inline.js` and `PhpTextRole.php`: signature, flags and
summary now travel as separate plain-text `data-*` attributes, and
`CodeInlineNode` receives `''` as help text, so `data-details` is empty.

The bundle that ships in 0.40.1 predates that change and reads only
`dataset.details`:

```js
// shipped in 0.40.1
t.dataset.details&&(r.innerHTML+=`<p>${l(t.dataset.details)}</p>`)

// rebuilt from the same commit
t.dataset.signature&&n.push(`<code>${l(t.dataset.signature)}</code>`),
t.dataset.flags&&n.push(l(t.dataset.flags)),
t.dataset.summary&&n.push(`<em>${l(t.dataset.summary)}</em>`),
t.dataset.details&&n.push(l(t.dataset.details)),
```

So the modal renders neither signature nor flags nor summary. Verified
in the published image
`ghcr.io/typo3-documentation/render-guides:0.40.1`
(`sha256:afc0ec1775c6cac35bfb13b06e7436ee618cc9e54baba083327cad1c9fb2277a`):
zero occurrences of `dataset.signature`.

## CSS and fonts are FontAwesome 7.2.0, the lock file says 7.3.1

`package-lock.json` pins FontAwesome 7.3.1 since TYPO3-Documentation#1333 (16 Jul). The
committed `theme.css` and the four `fa-*.woff2` files are 7.2.0 — the
last CSS build (TYPO3-Documentation#1290, 26 Jul) ran against outdated `node_modules`.
Icons added in 7.3.1 (`fa-matrix`, `fa-nextcloud`, `fa-codeberg`,
`fa-lotus` and others) resolve to nothing, and the animation timings
differ. The theme's own SCSS is in sync: no commit touches `assets/sass`
after TYPO3-Documentation#1290.

## Reach

`deploy-azure-assets.yaml` copies `resources/public/` verbatim to the
Azure CDN on every tag, so the stale files are also served from
`theme/typo3-docs-theme/0.40.1/`.

## What this PR does

Runs the documented build and commits its output. No source file is
touched.

Nothing in CI catches this — no workflow runs `npm run build`, and
`main.yaml` only runs `npm test`. A follow-up PR adds that guard.

Signed-off-by: Sebastian Mendel <github@sebastianmendel.de>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants