Articles
XXE Interview Questions for Defenders: Parser Settings, External Access, and Regression Tests
Practice defensive XXE interview answers with fail-closed XML parser settings, external-access controls, and side-effect regression tests.
An XML upload works in staging but a security review asks: “Can this parser read a local file or contact an internal URL while parsing an untrusted document?” A strong XXE interview answer does not stop at “turn off entities.” It identifies every XML-processing entry point, chooses a parser-specific deny policy, fails closed when the setting is unsupported, and proves in a regression test that no external access occurs.
This defender-focused guide uses a small Java DOM import flow and a safe local test design. Evidence boundary: OWASP's XML External Entity Prevention Cheat Sheet and Oracle's JAXP Security Guide support parser behavior and controls. The import flow, test matrix, and review rubric are original editorial examples. No candidate report is used for process claims.
Where does XXE enter the system?
An external entity is resolved during XML processing, before the application has a clean object graph to validate. If a parser accepts attacker-controlled declarations or references and resolves external resources, an import endpoint may cause the server to read files, make network requests, or consume excessive resources. OWASP describes XXE consequences including denial of service and server-side request forgery. An HTTP endpoint that merely receives a .xml filename is not the whole attack surface; the relevant event is parsing with a particular library and configuration.
Map the data flow: request body or uploaded file, decompression if any, XML parser, optional schema validation, XSLT transform, application mapping, and any later reparse. An endpoint can configure its first DOM parser safely and still call a schema factory or transformation engine that resolves an external resource. A library upgrade can change which JAXP provider newInstance() loads. OWASP explicitly notes JAXP's pluggable implementations, so a defense should identify the runtime provider and fail closed if a required setting is rejected.
This topic is adjacent to SSRF but has a different immediate control point. URL allowlisting at an application fetch client does not protect a parser that resolves a DTD before the application inspects parsed fields. Network egress restrictions reduce impact and are valuable defense in depth, yet the primary fix is to configure each XML processor to reject DTDs or external resolution as appropriate. The interview answer should name both layers without substituting one for the other.
The first decision: can you reject DTDs entirely?
OWASP calls complete DTD disabling the safest general approach when the application does not require DTDs. In the exercise, the import contract accepts simple <orders> documents and does not require entities, external schemas, or XInclude. Rejecting any DOCTYPE is therefore a clean policy: the parser should fail before it could resolve declarations. This is stronger than quietly replacing an external entity with empty text, because a rejected document signals that it violated the contract.
For a known Xerces-derived DOM parser, a practical Java configuration shape is:
DocumentBuilderFactory factory = DocumentBuilderFactory.newDefaultInstance();
factory.setFeature(
"http://apache.org/xml/features/disallow-doctype-decl", true);
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
factory.setXIncludeAware(false);
DocumentBuilder builder = factory.newDocumentBuilder();
builder.setEntityResolver((publicId, systemId) -> {
throw new SAXException("External XML resolution is disabled");
});
This is a defensive configuration sketch for a supported JDK implementation, not a copy-paste guarantee for every parser. newDefaultInstance() is available on Java 9 and later and selects the built-in implementation rather than a provider discovered through the ordinary lookup. The disallow-doctype-decl feature is implementation-specific. The application should not catch a ParserConfigurationException or IllegalArgumentException, log it, and continue with an unprotected factory. Fail startup or reject import until the chosen provider supports the policy. If the product must run on another provider, write a tested configuration for that provider instead of assuming these calls behave identically.
The empty ACCESS_EXTERNAL_DTD and ACCESS_EXTERNAL_SCHEMA values block access through those JAXP channels on implementations that support them; Oracle documents external-access properties and their precedence. They are useful defense in depth, but do not confuse them with a universal ban on all XML-related fetching. A separate SchemaFactory, Validator, or TransformerFactory may need its own settings, and a custom resolver can affect the resolution path. The explicit throwing resolver makes unexpected resolution visible in this example. Review the whole pipeline.
What if the business really needs a DTD?
Some legacy XML formats rely on entity declarations. Then a blanket DOCTYPE ban may break valid input, and the answer becomes more constrained. OWASP recommends disabling external general entities, external parameter entities, and external DTD loading together for relevant parser implementations; leaving one channel enabled can preserve an external-resolution path. A local catalog resolver can map a small set of approved identifiers to packaged resources and reject all others. That is a narrow dependency contract, not permission for the parser to fetch arbitrary file: or http: URLs.
Ask the owner to distinguish internal entities from external resources. Allowing internal DTDs can still expose entity-expansion denial-of-service risks if limits are absent. FEATURE_SECURE_PROCESSING helps impose implementation-specific processing limits, but OWASP warns it is not sufficient by itself to deny external access across processors. A solution that only calls setExpandEntityReferences(false) is also misleading: that option changes how entity references appear in the DOM tree, not whether the parser fetched a resource. These distinctions are common review traps.
If business input includes an external schema URL, prefer a pinned, packaged schema with a strict resolver or controlled catalog. Do not let an untrusted schemaLocation pick a network destination. Test schema validation separately from DOM parsing. If the system transforms XML with XSLT, review stylesheet import/include and document access as another entry point. For an interview, the strong phrase is “I enumerate every parser, validator, and transformer invoked by this import path, then enforce the same deny-by-default resource policy at each one.”
Build a regression test that measures access, not just exceptions
The exercise's test fixture set should include a normal accepted document, a document containing a DOCTYPE, a document that would request a local fixture file if external resolution were enabled, and one that would request a loopback test server. Keep these fixtures inside a controlled test environment; there is no need to include real secrets, cloud metadata addresses, or exploitable production payloads in a public interview answer. The expected result under the no-DTD contract is that the normal document parses, while the other documents are rejected before any external read or request.
The decisive assertions are zero resolver calls, zero loopback-server requests, and no fixture-file content in the parsed result or error output. Checking only for a thrown exception can be too weak: a parser might fetch a resource and fail later for an unrelated reason. A loopback server gives a measurable network side effect; a deliberately harmless temp file gives a measurable local side effect. Instrument or substitute the resolver where the API permits. Assert the application surfaces a safe validation error rather than returning parser internals to a client.
Run the test at more than one boundary. Unit-test the factory configuration with the exact runtime dependency set. Exercise the import API so that no alternative code path bypasses the factory. Add a test for schema validation or transformation if that path is used. In CI, log the parser implementation class and version so a provider change is visible. If the factory starts throwing on a new deployment, the test should fail rather than silently disabling the policy.
The test should also ensure the defense does not reject all XML. Parse a representative valid order document and compare a few fields with expected values. A security fix that makes the import unusable will often be rolled back under pressure; proving valid behavior alongside rejection makes the control durable. Measure input size and complexity limits separately because external-resource denial does not solve every XML denial-of-service pattern.
Walk through an incident review
Suppose a static scanner flags an XML parser at OrderImport.parse, but the team says its gateway blocks outbound traffic. Do not mark the finding false solely from the gateway claim. First identify the parser implementation and actual factory settings in the deployed build. Then trace whether input can include DTDs, whether the code invokes a validator or transformer, and whether egress controls cover local files as well as network. Record the exact path and test it in an isolated environment.
If the parser already rejects DTDs and the regression test proves no external resolution, explain that evidence in the triage record. If the settings are present but unsupported and swallowed, the code is vulnerable to configuration drift even if today's network policy blocks one outcome. Fix the fail-open error handling and keep network controls as defense in depth. If an approved schema truly requires local resolution, document the catalog entries and regression-test that an unknown identifier fails. Avoid a broad all external-access setting just to get one valid document working.
For rollout, ship the parser configuration with unit and integration tests, monitor rejection rates and import failures, and provide a clear remediation route for clients sending legacy DTDs. A surge in rejected documents may indicate incompatible partners or probing; it is not evidence by itself of compromise. Rollback should not mean restoring permissive parsing. A safer contingency can route known partner files through a tightly scoped, audited conversion process while the contract is corrected.
Distinguish three easily confused controls
DTD rejection stops declarations and simplifies the threat model when DTDs are unnecessary. It is the preferred contract for the exercise. External-access properties constrain protocols for DTDs and schemas on supporting JAXP processors; apply them to each relevant factory and verify precedence. Resource resolvers provide explicit mapping or denial and help detect attempted resolution. These controls reinforce each other, but a particular application's support matrix decides the exact implementation.
Do not say “secure processing equals no XXE.” Oracle and OWASP describe processing limits and external-access controls as related but distinct. Do not say “entity expansion disabled equals no file access.” Do not say “we only parse trusted partner XML” without explaining how partner content is authenticated, whether it can contain third-party data, and whether a compromised source could reach the parser. A robust boundary treats imported XML as untrusted until parsed under a restrictive policy.
How to answer in a 15-minute interview
Open with the data-flow map and contract: “This endpoint accepts order elements; it does not need DTDs.” State the primary setting: reject DOCTYPE using a parser implementation that supports the feature. Add empty external-access properties and a deny resolver where applicable. Explain that configuration errors stop the deployment. Then give two regression assertions: valid XML still parses, and a local/loopback probe produces no read or request. Finish by naming the validator/transformer surfaces and a production metric for rejected XML.
If asked about alternate languages, resist copying a Java recipe into Python or .NET. Each parser API has its own defaults and switches; consult the maintained library guidance and test the installed version. The general reasoning transfers: enumerate entry points, deny external resolution, bound resource use, fail closed, and verify side effects. The exact configuration calls do not.