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 |
|---|---|
|
refused, |
|
no |
|
no |
|
yes |
|
no |
|
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.