Skip to content

deps: the XSLT engine at 2.9.0, for an advisory that names the pin we ship - #54

Merged
elvogel merged 3 commits into
mainfrom
deps/engine-2.9.0
Oct 15, 2026
Merged

elvogel merged 3 commits into
mainfrom
deps/engine-2.9.0

Conversation

@elvogel

@elvogel elvogel commented Oct 15, 2026

Copy link
Copy Markdown
Contributor

Moves PhoenixmlDb.Xslt 2.7.0 -> 2.9.0 (with PhoenixmlDb.XQuery 2.9.0 and PhoenixmlDb.Core 2.2.0 -> 2.5.0).

Why now

GHSA-5697-c8qg-472f (high, published 2026-10-15) names every engine release up to and including 2.7.0 — the pin on main and the pin 0.2.5 shipped. It is patched in 2.8.0. Two of its items are reachable through --stylesheet, which compiles and runs a caller's stylesheet inside docmd's own process:

  • A static expression could read our environment. A shadow attribute, a use-when or a static variable is evaluated while the stylesheet compiles, by a second evaluator that read the real process environment. At run time fn:environment-variable() has always answered nothing. No resource policy is needed to reach this.
  • An import opened by name. Before compiling, the processor opened the file of each xsl:import / xsl:include directly — without the policy and without the host's resolver — even where a use-when excluded the instruction.

Measured here, not taken from the advisory. The same stylesheet, a shadow attribute reading one variable, run on both engines built in their own worktrees:

Engine Result
2.7.0 [a-value-no-stylesheet-may-read][][] — the value is in the output
2.9.0 [][][]

What is in the branch

  • Directory.Packages.props plus all three packages.lock.json files, regenerated with --force-evaluate.
  • A canary in EnginePremiseTests: a stylesheet asks for the environment three ways — a shadow attribute, a runtime call, and the list of names — and must be answered nothing each time. It fails on 2.7.0, so it is not vacuous and the pin cannot slide back under 2.8.0 quietly.
  • The changelog entry.

Verification

  • Conversion is byte-identical. All 13 corpus documents, each arm from its own worktree with the loaded PhoenixmlDb.Xslt assembly checked against the package of that version first: diff -r over both output trees reports nothing — 52 files, 4,877,492 bytes each side.
  • 384 tests: 383 pass, 1 skip (the opt-in corpus audit). Build is clean, 0 warnings.
  • Schema-awareness is now the default in 2.9.0. The built-in stylesheet declares no validation and imports no schema, so the built-in path is untouched; a caller's stylesheet that relied on XTSE1660 to refuse type or validation now compiles instead. XsltTransformer.SchemaAware = false asks for a basic processor.
  • No performance claim. 373 s vs 358 s for the whole corpus, one run each, inside this machine's same-binary drift. Not benchmarked further: engine timings are secondary to conformance.

Relation to the other open PRs

🤖 Generated with Claude Code

https://claude.ai/code/session_018wZEgtuzaZPswykiGEBxbz

Lucas Vogel and others added 3 commits October 15, 2026 12:30
Takes PhoenixmlDb.Xslt 2.9.0, which carries PhoenixmlDb.XQuery 2.9.0 and
PhoenixmlDb.Core 2.5.0. The pin moves two releases: 2.8.0 holds security
fixes for a host that compiles or runs a stylesheet from an untrusted
party, which is what --stylesheet makes of docmd.

All three lock files move with the pin. Regenerated with --force-evaluate,
because a lock file records the resolved transitive versions as well as the
requested one, and CI restores with --locked-mode.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018wZEgtuzaZPswykiGEBxbz
GHSA-5697-c8qg-472f (high) names every PhoenixmlDb.Xslt up to and including
2.7.0, which is the version 0.2.5 shipped. A shadow attribute, a use-when or
a static variable is evaluated while the stylesheet compiles, by a second
evaluator, and that one read the environment of the host process; at run time
the engine has always answered nothing. --stylesheet compiles a caller's
stylesheet in our own process, so the licence key and anything a build put in
the environment were readable, with no resource policy needed to reach it.

The canary asks three ways -- a shadow attribute, a runtime call, and the
list of names -- and expects nothing back each time. Checked against both
engines in their own worktrees: on 2.7.0 the shadow attribute writes the
value into the result and the test fails; on 2.9.0 it writes an empty string.
So the test says something, and the pin cannot slide back under 2.8.0
quietly.

The changelog records the bump: byte-identical conversion of the whole
corpus, the schema-aware default of 2.9.0, and no performance claim.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018wZEgtuzaZPswykiGEBxbz
@elvogel
elvogel merged commit 486bfbb into main Oct 15, 2026
1 check passed
@elvogel
elvogel deleted the deps/engine-2.9.0 branch October 15, 2026 17:07
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.

1 participant