CVE-2025-66371 Overview
CVE-2025-66371 is an XML External Entity (XXE) vulnerability in peppol-py versions before 1.1.1. The flaw stems from an insecure Saxon processor configuration in the invoice validation routine. When the library validates XML-based Peppol invoices, the XML parser can resolve external entity references that point to arbitrary URLs or local filesystem paths. An attacker who can supply a crafted invoice document can force the parser to read files from the host filesystem and exfiltrate their contents to a remote server. The issue is tracked under CWE-611: Improper Restriction of XML External Entity Reference.
Critical Impact
A remote attacker with the ability to submit invoice XML to a vulnerable peppol-py deployment can read arbitrary files accessible to the validation process and exfiltrate them over the network.
Affected Products
- peppol-py versions prior to 1.1.1
- Applications embedding peppol-py for Peppol invoice validation
- Deployments using the Saxon XSLT processor through PySaxonProcessor without protocol restrictions
Discovery Timeline
- 2025-11-28 - CVE-2025-66371 published to NVD
- 2026-10-08 - Last updated in NVD database
Technical Details for CVE-2025-66371
Vulnerability Analysis
The peppol-py library validates Peppol electronic invoices by running Schematron rules compiled to XSLT, which are executed through the Saxon XSLT 2.0 processor via PySaxonProcessor. By default, Saxon permits document retrieval using multiple URI schemes, including file, http, and https. The validation path exposes this capability to attacker-controlled XML, enabling classic out-of-band XXE behavior through XSLT document() calls or external entity resolution.
An attacker crafting a malicious invoice can reference external DTDs or documents that the Saxon processor fetches during validation. Because the processor runs server-side with the privileges of the invoicing application, retrieved content can include local files such as configuration, credentials, or application source.
Root Cause
The root cause is a missing allow-list on URI protocols in the Saxon configuration. The vulnerable code instantiated PySaxonProcessor without setting the http://saxon.sf.net/feature/allowedProtocols property, leaving Saxon's permissive default behavior intact. External entity and document references were therefore resolved during XSLT-based Schematron validation.
Attack Vector
Exploitation requires an attacker who can submit an XML invoice to the validation endpoint. The crafted document includes an external entity or an XSLT document() call pointing at either a file:// URI for local disclosure or an http:// URI for out-of-band exfiltration. The parser resolves the reference during validation, reads the targeted resource, and may embed its contents in a request to the attacker's host.
# Security patch in src/peppol_py/validation.py
# Prevents Saxon URL access to avoid XXE (PR #16)
with PySaxonProcessor(license=False) as proc:
# Prevent XXE: disallow access to any type of URL
proc.set_configuration_property("http://saxon.sf.net/feature/allowedProtocols", "")
for validation_xsl_file in schematron_xsls:
if not os.path.exists(validation_xsl_file):
# Resolve internal files
...
Source: peppol-py commit 349a4bf
Detection Methods for CVE-2025-66371
Indicators of Compromise
- Outbound network connections initiated by the peppol-py validation process to unexpected external hosts during invoice processing.
- Invoice XML payloads containing <!DOCTYPE> declarations, external entity references, or XSLT document() calls pointing to file://, http://, or https:// URIs.
- Unexpected filesystem read access on sensitive paths (for example, /etc/passwd, application config files) by the Python process hosting peppol-py.
Detection Strategies
- Inspect inbound invoice XML for DOCTYPE declarations and external entities before passing documents to validation.
- Monitor the peppol-py version in use via dependency scanning and flag any version earlier than 1.1.1.
- Correlate Saxon or PySaxonProcessor runtime logs with outbound DNS and HTTP activity to identify anomalous resolution attempts.
Monitoring Recommendations
- Enable egress logging for application servers that process Peppol invoices and alert on connections to non-allowlisted destinations.
- Record process-level file access telemetry on hosts running peppol-py to detect reads of sensitive files during invoice workflows.
- Track application error logs for Saxon document resolution failures, which often accompany failed or probing XXE attempts.
How to Mitigate CVE-2025-66371
Immediate Actions Required
- Upgrade peppol-py to version 1.1.1 or later, where the Saxon processor is configured to disallow all external URL protocols.
- Inventory all services that ingest third-party invoice XML and prioritize patching those exposed to untrusted submitters.
- Rotate any credentials or secrets stored on hosts running vulnerable versions if exploitation cannot be ruled out from logs.
Patch Information
The fix is published in peppol-py release 1.1.1 and merged via Pull Request #16. The patch sets the Saxon configuration property http://saxon.sf.net/feature/allowedProtocols to an empty string, preventing the processor from resolving any external URI during Schematron validation. Review the commit at 349a4bf for implementation details.
Workarounds
- If immediate upgrade is not possible, patch the local validation.py to set the Saxon allowedProtocols property to an empty string before invoking Schematron XSLTs.
- Pre-validate inbound XML and reject any document containing a <!DOCTYPE> declaration or external entity reference prior to Saxon processing.
- Restrict egress network access from invoice-processing hosts so that out-of-band exfiltration channels are blocked at the perimeter.
# Pin the fixed version in requirements files
pip install 'peppol-py>=1.1.1'
# Verify the installed version
python -c "import peppol_py, importlib.metadata as m; print(m.version('peppol-py'))"
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

