software security

libexpat gets Munich funding: what a “security vacation” changes for XML parsing

libexpat gets Munich funding: what a “security vacation” changes for XML parsing

When a piece of software is quietly everywhere, it’s easy to forget that humans still maintain it.

libexpat (the Expat XML parser library) sits behind a surprising amount of XML processing. Expat is a stream-oriented XML parser written in C: instead of requiring you to load the entire document into memory, you register handlers (callback functions) and feed the parser chunks of input. (libexpat.github.io) It’s fast, it’s licensed under the MIT/X Consortium license, and it shows up in many open-source stacks. ()

So when the maintainer announced that libexpat would be funded by the City of Munich for up to six months—right as a “security vacation” ended—what’s the real technical story underneath the headline? (github.com)

What is libexpat/Expat, technically (and why “streaming” matters)

A stream-oriented parser is an XML parser that processes input as it arrives. That “as it arrives” detail is not cosmetic:

  • You can parse very large XML documents that don’t fit in RAM.
  • You can start reacting to content early (for example, when a start tag appears).
  • You can control resource usage by chunking the input.

Expat’s model is event-driven. You create a parser instance, then set handler functions for events like “start element” or “character data”. Those handlers get called during parsing. ()

The important beginner mental model: Expat isn’t trying to be a full “in-memory XML database.” It’s more like a tokenizer with a structured understanding of XML syntax. That makes it useful, but it also means the parser’s internal state machine is constantly updated while it’s consuming untrusted bytes.

The “security vacation” concept: capacity is a security primitive

Here’s the part that feels surprising until you’ve worked on security fixes long enough: receiving vulnerability reports and fixing them are not the same task.

In June 2026, libexpat’s maintainer created an issue stating that the project would not accept (or otherwise handle) new vulnerability reports until 2026-08-01. () The reason wasn’t “we don’t care.” It was “we can’t process at a sustainable pace.” The announcement explicitly referenced pausing fuzzing/AI intake and continuing work on already-known unfixed issues. ()

A good way to understand this is queueing theory, the study of waiting lines and backlogs. Every incoming report has a cost: triage time, reproduction time, test writing, review time, and release coordination time. If the queue grows faster than it’s drained, work quality drops—or deadlines slip—until the whole system becomes less safe.

That’s why a “security vacation” is more than scheduling. It’s risk management by limiting how much uncertain input the maintainer can ingest while still finishing fixes.

What work had to happen anyway: unfixed issues aren’t idle time

The maintainer also pointed to existing unfixed non-public security issues, maintained as a living list in GitHub issue #1160. () That issue shows a timeline of reported issues and associated work items (mostly in the form of draft pull requests) with several still not resolved publicly at the time of writing. ()

This matters because it explains the technical shape of the funding period: money buys focus, but it also buys time for the unglamorous steps—writing regression tests, hardening edge cases, and validating fixes against tricky parsing paths.

A concrete example: UTF-16 conversion bugs can become infinite loops

One of the actively discussed items during this period was a draft pull request, #1296, described as fixing an out-of-bounds read and an infinite loop in *_toUtf16 functions. ()

Let’s translate that into plain engineering terms:

  • An out-of-bounds read is when code reads memory past the valid range of an array/buffer. Even if it doesn’t immediately crash, it can cause undefined behavior and sometimes exploitable conditions.
  • An infinite loop is control flow that never reaches its termination condition, so the parser can get stuck consuming CPU indefinitely.
  • *_toUtf16 indicates character encoding conversion to UTF-16.

UTF-16 is tricky because it uses surrogates (special code units) to represent Unicode code points above U+FFFF. If a parser misclassifies surrogate halves, conversion logic can go down the wrong path and fail to advance correctly.

This is a recurring theme in XML security: “XML” isn’t just angle brackets and tags. XML documents contain text, encodings, and name rules that interact with parser internals continuously.

XML security isn’t only about “hackers”; it’s about parser behavior

Expat’s own XML security documentation spells out why “parsing XML” is a security-sensitive operation.

XXE (XML External Entity)

XML External Entity (XXE) attacks rely on the parser resolving external resources referenced from the XML—using file://, https://, ftp://, or relative URLs. () Expat’s documentation notes that by default it does not access external URLs, and it will only support URL access if an external entity handler is explicitly configured (via XML_SetExternalEntityRefHandler). ()

That last sentence is where real-world risk often appears: many wrapper libraries or application configurations turn “external entity handling” on without realizing it.

Billion laughs (resource exhaustion)

The “billion laughs attack” is a denial-of-service scenario where recursively nested entities expand into massive output from a small input document. () Expat includes countermeasures: it stops processing if the output is more than 100× larger than the input and larger than 8 MiB. ()

Why does this show up in a story about maintainers and funding? Because these protections aren’t just “configuration flags.” They’re code paths that have to be kept correct as the parser evolves.

A question that comes up a lot

Why do XML parsers keep getting security bugs even though XML is “just text”? Because the parser is a state machine that repeatedly interprets structured data under adversarial conditions—encodings, recursion, entity rules, and buffer boundaries are all fertile ground for bugs.

Adding XML 1.0r5 support: it’s mostly about character classes and Unicode edge cases

The funding priorities weren’t only about patching security holes. Another listed target was adding support for XML 1.0r5.

At a high level, supporting XML 1.0r5 means correctly implementing rules for what characters are allowed in XML names.

In XML, tag names and other identifiers use the concepts of:

  • NameStartChar: the set of Unicode characters allowed as the first character of a name.
  • NameChar: the set of Unicode characters allowed in the rest of a name.

One libexpat GitHub issue (#171) focuses on correcting the parser’s behavior around XML 1.0r5/1.1 start and name characters, including a test that inserts many Unicode characters into documents to validate expectations. ()

But there’s a reason this is non-trivial: XML character validity depends on Unicode ranges, and newer Unicode planes introduce surrogate-related complications.

And to make it real: Expat’s own “common pitfalls” documentation states that XML 1.1 and XML 1.0 Fifth Edition are not supported. () That’s exactly the gap a sustained maintenance sprint is meant to tackle.

There’s also an older draft pull request (#711) titled “[draft] Support XML 1.0r5 and above”, describing changes to internal name character maps and updates to tests for UTF-8 start tags and long Unicode characters. ()

So the technical work is less about “turning on a feature flag,” and more about making sure the tokenizer and name table logic agree with the XML standard’s Unicode rules.

“Up to six months” of funding: what the City of Munich sabbatical changes

The City of Munich’s Open Source Sabbatical is designed to let qualified developers work on an open source project for a limited period, including options for external developers with financial compensation for lost earnings. (opensource.muenchen.de) The program description also discusses options like target compensation around 60% of usual salary for external developers. ()

From a technical perspective, this is important because parsing code needs ongoing stewardship:

  • security fixes must be validated and regression-tested,
  • standards support improvements require careful interoperability checks,
  • and maintainability work (like refactoring internals, syncing build systems, and improving test coverage) reduces the chance of future regressions.

Even in open source, time is the bottleneck.

A small “streaming parser” example with Expat

If the stream model feels abstract, here’s the smallest useful idea: parse in chunks and react to start tags.

#include <expat.h>
#include <stdio.h>
#include <string.h>

static void on_start(void *userData, const char *name, const char **atts) {
 (void)userData;
 (void)atts;
 printf("start: %s\n", name);
}

int main(void) {
 XML_Parser p = XML_ParserCreate(NULL);
 if (!p) return 1;

 XML_SetElementHandler(p, on_start, NULL);

 const char *chunk1 = "<root><item>";
 const char *chunk2 = "Hello</item></root>";

 if (XML_Parse(p, chunk1, (int)strlen(chunk1), 0) == XML_STATUS_ERROR)
 return 2;
 if (XML_Parse(p, chunk2, (int)strlen(chunk2), 1) == XML_STATUS_ERROR)
 return 3;

 XML_ParserFree(p);
 return 0;
}

The key point: Expat is happy even though the input arrives in pieces. That’s the same mechanism that makes streaming parsers efficient—and that also means the internal state machine is always being exercised.

Where this leaves you as a user of XML parsers

As of mid-2026, Expat’s release news shows a steady stream of security-fix releases, including Expat 2.8.2 announced on 2026-06-25. (libexpat.github.io)

The technical takeaway from the Munich funding story is not “a parser is safe because it’s open source.” It’s the opposite: security depends on sustaining the people and processes that keep the parser correct.

When a maintainer can focus—rather than constantly switching between day job, reviews, and triage backlog—standards work (like XML 1.0r5 character rules) and security work (like edge-case bugs in encoding conversion) can progress together.

And that’s the hidden engineering win behind the headline: fewer forgotten edge cases, more tests for the weird corners, and a parser that behaves predictably under adversarial input.

ahsan

ahsan

Hello! I am Mr Ahsan, the writer of the Website. I am from Netherland. I like to write about technology and the news around it.

Comments (0)

No comments yet. Be the first to respond!

Leave a Comment

Your comment will be visible after review.