Skip to content

Upgrade @xmldom/xmldom from 0.9.10 to 0.9.12 to close its security advisories - #147

Merged
NSchatz merged 1 commit into
mainfrom
harness/106-xmldom-0912-runtime-alerts
Oct 19, 2026
Merged

NSchatz merged 1 commit into
mainfrom
harness/106-xmldom-0912-runtime-alerts

Conversation

@NSchatz

@NSchatz NSchatz commented Oct 19, 2026

Copy link
Copy Markdown
Contributor

The published 0.1.0 pins @xmldom/xmldom 0.9.10, which every install of @cosyte/ccda gets. pnpm audit --prod reported 13 advisories against it (11 high, 2 moderate), all fixed in 0.9.12. This moves the exact pin to 0.9.12.

Finish line

  • pnpm why @xmldom/xmldom --prod: @xmldom/xmldom@0.9.12, found 1 version.
  • pnpm audit --prod: no known vulnerabilities (exit 0). The 8 dev-scope advisories are out of scope here.
  • Patch changeset: .changeset/xmldom-security-upgrade.md.
  • Gate, run locally with pnpm 10.34.5: typecheck, lint, format:check, the em-dash, internal-refs and agent-notes checks, phi-scan, test:coverage (43 files, 1375 passed, 1 skipped, coverage gates green), build, attw, a CJS and ESM import smoke check, the examples job (typecheck, lint, 4 of 4 run) and pnpm conformance (15 built documents and 20 corpus round trips, committed report unchanged).

What changed underneath, and how it was checked

No source change was needed. I read the 0.9.10 to 0.9.12 changelog and the lib/ diff first, then parsed the same inputs through the built package against each version:

  • every fixture document, 26 crafted edge cases (end tags with trailing content, unbound prefixes, < in tag names, duplicate attributes, xmlns rebinding, stylesheet and malformed processing instructions, CDATA, nested namespace declarations, a BOM) and 3,000 seeded mutations gave identical warnings, model readings, serialized bytes and fatal codes;
  • buildCcda emitted identical bytes for all fifteen conformance cases.

The serializer never passes requireWellFormed, and the builder and editor create elements only under constant names, so the serializer and creation-time advisories do not change what ccda emits. The parse-time denial-of-service fixes are reachable through parseCcda, which is the real gain for users.

Tests (test/security.test.ts)

Hostile input stays linear. Three shapes from the advisories run through parseCcda under a 4,000 ms budget:

Shape 0.9.12 0.9.10
unterminated processing instruction, 70k spaces ~9 ms ~21 s
one element, 80,000 attributes ~0.3 s ~16 to 20 s
40k < inside a malformed tag ~0.5 s ~20 to 23 s

The namespace-map advisory (GHSA-965w-775f-mr7g) has no case. Its fix is to memory, not time: at depth 10,000, 0.9.10 used 3 GB against 0.9.12's 200 MB, but 0.9.12 still took about 2.5 s, so a wall-clock budget cannot separate the versions cleanly.

What the parser reports differently, and what ccda does with it:

  • An end tag followed by a line break and trailing content (GHSA-6h8r-xr42-gp59) is now reported at the error level. buildDom escalates only fatalError, so the document parses as before, with the same warning codes and serialized bytes as the clean document.
  • A DOMException raised while building the DOM (an unbound prefix) now arrives as a fatalError, and the parser's error keeps it as cause, which quotes the element name. ccda still throws NOT_WELL_FORMED_XML with the registry message, an empty position and no cause. A probe asserts the parser-side cause exists, so the case cannot pass vacuously.
  • An xml-stylesheet instruction, the shape 0.9.11's rewritten PI grammar touches and real C-CDA files often carry, round-trips verbatim. No test carried one before.

Negative control: with node_modules/@xmldom/xmldom pointed at 0.9.10, the three timing cases fail (21.9 s, 19.6 s, 23.3 s) and so does the cause probe. The end-tag and stylesheet cases pass on both versions, as intended: they pin ccda's outcome, not the parser's.

Left as is, for the owner to decide

ccda's onError drops every warning and error report from the parser, including the new end-tag one. Surfacing these as a ccda warning would add a warning code (a minor bump) and is a decision of its own; the end-tag test is where that decision will show.

Harness-Task: 106

🤖 Generated with Claude Code

…visories

The published 0.1.0 pins @xmldom/xmldom 0.9.10, and every install of
@cosyte/ccda gets it. pnpm audit --prod reported 13 advisories against
it (11 high, 2 moderate), all fixed in 0.9.12. The pin moves to 0.9.12,
still exact; pnpm why @xmldom/xmldom --prod now shows 0.9.12 and nothing
older, and pnpm audit --prod reports no known vulnerabilities.

No source change was needed. The 0.9.10 to 0.9.12 changelog and the lib
diff were read first, then the upgrade was run differentially: the same
inputs through the built package against each version. Every fixture
document, 26 crafted edge cases and 3,000 seeded mutations gave the same
warnings, model readings, serialized bytes and fatal codes, and
buildCcda emitted the same bytes for all fifteen conformance cases.
pnpm conformance reproduces the committed report byte for byte.

test/security.test.ts gains two blocks:

- Three denial-of-service shapes from the advisories, parsed through
  parseCcda under a 4 s budget: an unterminated processing instruction,
  an element with 80,000 attributes, and a run of `<` inside a malformed
  tag. On 0.9.12 the slowest takes about 0.5 s; on 0.9.10 they take
  20 to 23 s and fail. The namespace-map advisory is a memory fix and
  0.9.12 is still super-linear in time on that shape, so it has no case.
- What the parser now reports differently. An end tag followed by a line
  break and trailing content is reported at the error level, which
  buildDom tolerates, so the document parses as before. A DOMException
  raised while building the DOM now arrives as a fatalError whose cause
  quotes the element name; ccda still throws NOT_WELL_FORMED_XML from
  the registry with no cause. An xml-stylesheet instruction, which 0.9.11's
  rewritten PI grammar touches, round-trips verbatim.

Run against 0.9.10, the three timing cases and the cause probe fail; the
other two pass on both, as they pin ccda's outcome rather than the
parser's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@NSchatz
NSchatz merged commit b7faca4 into main Oct 19, 2026
11 checks passed
@NSchatz
NSchatz deleted the harness/106-xmldom-0912-runtime-alerts branch October 19, 2026 22:56
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