Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

xmlfend

Flag XML parsers that can process external entities — before an attacker feeds them one.

An XML parser left with its defaults will happily read a document like this:

<?xml version="1.0"?>
<!DOCTYPE r [ <!ENTITY x SYSTEM "file:///etc/passwd"> ]>
<r>&x;</r>

…resolve that external entity, and hand the contents of /etc/passwd back in the response. Point the entity at an internal URL instead and it becomes SSRF; point it at a nested-entity bomb and it becomes a denial of service. This is XXE — XML External Entity injection (CWE-611), and the fix is always the same: configure the parser to refuse DOCTYPEs and external entities. The trouble is that the insecure configuration is usually the default one, so the vulnerability is a line of code that looks perfectly ordinary.

xmlfend is a zero-config static gate that scans your code for XML parsers instantiated or used in an unsafe way, and flags them — grounded in the OWASP XXE Prevention Cheat Sheet.

$ xmlfend .

● 2 insecure XML parser(s):
  app/parse.py:19  lxml XML parser created without disabling external-entity resolution.
      ↳ lxml resolves external entities unless you pass resolve_entities=False ...
      [XX001 Python/lxml]
  app/parse.py:24  Standard-library XML parser used on input without defusedxml.
      ↳ xml.etree / xml.dom.minidom / xml.sax do not defend against external entities ...
      [XX001 Python/stdlib]

2 blockers · 0 warnings

Exit code 1 when it finds an insecure parser, so it drops straight into pre-commit or CI.

How it works

For each source file, xmlfend looks for a known XML parser used in a risky construct (the trigger), then checks whether the file also applies that parser's XXE hardening (the safe marker). If the risky construct is present and the hardening is not, it reports the line.

The safe-marker short-circuit is what keeps false-positives low: a file that imports defusedxml, sets resolve_entities=False, calls libxml_disable_entity_loader(true), sets disallow-doctype-decl, uses DtdProcessing.Prohibit, or nulls the XmlResolver is treated as safe. No code is executed and no network calls are made — it's a single static binary.

Coverage: Python (lxml, xml.etree/minidom/sax), Java/Kotlin/Scala (JAXP factories), PHP (libxml, simplexml, DOMDocument), .NET (XmlReaderSettings, XmlDocument), Node.js (libxmljs), Ruby (Nokogiri).

Install

go install github.com/jay-tank/xmlfend@latest

Or build from source: go build -o xmlfend .

Usage

xmlfend                  # scan the current directory
xmlfend ./src            # scan a path
xmlfend --strict         # treat warnings (e.g. an inline DTD) as failures too
xmlfend --json           # machine-readable output

In CI

- run: go run github.com/jay-tank/xmlfend@latest ./ --strict

Exit codes: 0 clean · 1 an insecure parser (or any finding under --strict) · 2 usage error.

Rules

Rule Severity What
XX001 blocker A known XML parser is instantiated / used in a way that can process external entities or a DTD, with no hardening present
XX002 warning An explicit DTD / entity declaration (<!DOCTYPE ... [, <!ENTITY ...>) appears in source

Every finding cites the OWASP XXE Prevention Cheat Sheet and CWE-611 in its hint.

Suppressing false positives

xmlfend is a heuristic gate that reads each file on its own. If you harden the parser in a shared factory (a different file), add a xmlfend:ignore comment on the flagged line or the line directly above it, or list a path substring in a .xmlfendignore file (one per line, # for comments).

Scope

xmlfend answers one question well — "is this XML parser configured to keep external-entity / DTD processing on?" — across languages, as a fast static gate. It is a line/file-based heuristic: it does not build a full data-flow graph, so it favors the honest, low-noise call (a file that shows the hardening is treated as safe even if the hardening technically applies to a different parser in the file). That trade catches the overwhelmingly common case — a parser left on its insecure defaults — without drowning you in noise.

License

MIT © Jay Tank

About

A zero-config static gate that flags XML parsers configured to process external entities / DTDs - the root cause of XXE (CWE-611). Language-agnostic, single Go binary.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages