XML reader configured to fetch external resources

ID

csharp.insecure_xml_parser_configuration

Severity

low

Remediation Complexity

trivial

Remediation Risk

low

Remediation Effort

low

Resource

Misconfiguration

Language

CSharp

Tags

ASVS50:v1.5.1, CWE:611, CWE:776, OWASP:2025:A02

Description

An XML reader is configured so that it retrieves the files and URLs a document names in an external entity. A document from an untrusted source can then make the process read a local file or issue a request of the attacker’s choosing.

Rationale

csharp.xml_entity_injection reports XXE when a data path can be followed from an external input to the reader. That needs the input to be visible: a reader configured in a codec or a helper class, where the caller lives in another project, has no source to follow and is reported by nothing. This detector reports the configuration, which is unsafe on its own terms.

Its severity is low because the finding says nothing about whether attacker-controlled XML actually reaches the reader — when that can be shown, csharp.xml_entity_injection reports it as critical, and this finding is dropped as a duplicate.

Only an explicit opt-in is reported

Unlike the Java rule, this one never reports a default. Modern .NET refuses external entities out of the box, so reporting a plain XmlReader.Create or new XmlDocument() would be a false positive on every current project.

The behaviour was measured against the .NET 10 runtime rather than taken from documentation, using a document whose entity points at a file of known content so that expansion is observable instead of being inferred from the absence of an exception:

Configuration Entity expanded

XmlReader.Create(input) — defaults

refused, DtdProcessing is Prohibit

DtdProcessing = Parse, resolver left at its default

no

DtdProcessing = Parse, XmlResolver = null

no

DtdProcessing = Parse, XmlResolver = new XmlUrlResolver()

yes

new XmlDocument().LoadXml(..) — defaults

no

new XmlDocument { XmlResolver = new XmlUrlResolver() }

yes

So neither DTD parsing nor a resolver is enough alone on a reader-settings object: the pair is what does it. On a document object, which has no DtdProcessing property, the resolver alone is enough.

That gives a test that does not need the receiver’s type, which matters because a property assignment does not carry one. A fetching resolver is reported when the same receiver also enables DTD parsing, or when it carries no DtdProcessing setting at all. The only combination left alone is a resolver next to DtdProcessing.Prohibit or .Ignore.

ProhibitDtd = false is also reported. It is the legacy spelling, removed in .NET Core, but wherever it still exists it is an explicit opt-in to DTD processing.

Examples

Reported — the DTD is read and there is a resolver to fetch with:

var settings = new XmlReaderSettings {
    DtdProcessing = DtdProcessing.Parse,
    XmlResolver = new XmlUrlResolver()          // reported
};
return XmlReader.Create(input, settings);

Reported — a document type has no DtdProcessing property, so the resolver alone does it:

var doc = new XmlDocument { XmlResolver = new XmlUrlResolver() };   // reported
doc.LoadXml(xml);

Not reported — the DTD is parsed but there is nothing to fetch with:

var settings = new XmlReaderSettings { DtdProcessing = DtdProcessing.Parse };
return XmlReader.Create(input, settings);

Remediation

Leave the defaults alone where the documents parsed need no DTD:

return XmlReader.Create(input);

Where a DTD must be read, keep the resolver out:

var settings = new XmlReaderSettings {
    DtdProcessing = DtdProcessing.Parse,
    XmlResolver = null
};

Where external resources really are required, restrict them with a policy rather than an open resolver:

var permitted = new PermissionSet(PermissionState.None);
permitted.AddPermission(new WebPermission(NetworkAccess.Connect, "https://schemas.acme.com/"));
settings.XmlResolver = new XmlSecureResolver(new XmlUrlResolver(), permitted);

Limitations

The receiver of a property assignment is matched by the text it was written as, within the enclosing method, so a reader configured across method boundaries or through a helper is not correlated. A resolver installed on a receiver whose DtdProcessing was set in another method is reported, since an absent setting cannot be told from a document type that has none.

© 2026 Xygeni. All rights reserved