Hacker Summer Camp Special: Get 40% OFF with code HACKERCAMP40. Limited time only!

Pixelated Secrets: From Thumbnail Previews to AWS Credentials

PUBLISHED:
August 21, 2025
|
BY:
Abhishek P Dharani
Ideal for
Security Champion
Security Leaders
Cloud Engineer

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

Introduction

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.

File Uploads and the Problem of Trust

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).

What is 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

What We Observed in REDACTED’s Asset Management Module

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, 

  • A media upload interface with an “upload by URL” feature. We have a URL parameter that links to our media assets. A plain old blind SSRF is evident but not juicy!

  • An extension whitelist controlled via a parameter named assetTypeVsSupportedExtensionsMap.

  • Uploads triggered a PreviewURL—suggesting backend processing of the media files. The image below showcases the previewURL attribute,  in the response, linking to a png image of the media uploaded on the REDACTED cdn.

  • So there is some functionality in the backend tasked at generating media preview thumbnails

That meant something on the backend was:

  1. Downloading our file.

  2. Rendering it.

  3. Generating a thumbnail image.

  4. Hosting that image on a CDN.

But what was doing the rendering?

Identifying the Backend Processor via HTML Pingbacks

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.

HTML File as a Probe

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.

The Result?

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 – A Useful, Dangerous Tool

LibreOffice is an open-source office suite commonly used in server environments for headless document processing—automated conversions, thumbnail generation, PDF exports, etc.

Why is this a problem?

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.

Who’s a good boy? ODT! Fetch Metadata To Achieve Full SSRF

Crafting the Payload

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

Entire Attack Flow: The Whole Summary and AWS Credentials Extraction

‍

The Entire Attack Flow 

‍

  1. Upload the malicious .odt via the “upload by URL” feature.

  2. Backend downloads and passes it to LibreOffice. We also know the backend runs on AWS.

  3. LibreOffice parses the .odt file in order to get the document “preview ready”

  4. It connects to the AWS metadata endpoint.

  5. The fetched data is rendered in the document within the text area frame.

  6. A thumbnail is generated from the document.

  7. The thumbnail (containing the AWS response) is stored on a CDN.

  8. We retrieve the image and extract the AWS credentials.

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

What This Means – Broader Security Lessons

This exploit didn’t involve technically super complex chains or obscure bugs. It relied on:

  • A file upload interface that allowed remote URLs with client-side file extension whitelist check.

  • Over-trusting a document rendering engine. LibreOffice has many features such as UpdateDocMode that could be disabled

  • Lack of isolation when processing user content. Lack of Network level restrictions for SSRF.

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
);

Broader Lessons

  1. Never trust uploaded files—even when processed by well-known tools.

  2. SSRF is alive and well in cloud-native apps—especially when metadata services are exposed.

  3. LibreOffice (and similar tools) can introduce significant risk in automated pipelines.  Always go with required configurations and nothing more.

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

  1. Defense-in-depth matters. Even if the CDN was hardened, the thumbnail generation step was a critical weak point.

  2. Logging and isolation of rendering services could have detected or prevented this.

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.

Conclusion

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.

Abhishek P Dharani

Blog Author
Hey, I’m Abhishek P Dharani, Senior Security Engineer at we45, self-taught cyber ninja, and professional breaker of things (don’t worry, I put them back together… usually). If there’s a vulnerability lurking in an app, I’ll find it faster than you can say “Oops, we left that API exposed.” I thrive on chaining bugs, finding quirky exploits, and making security engineers everywhere nervous (in a good way, I promise). Offensive security? I love it. Defensive security? Also love it. Automating my way out of doing boring stuff? Absolutely. When I’m not hacking away at cloud applications, you’ll find me smashing shuttlecocks in badminton, scoring runs in cricket, or attempting to bowl a perfect strike (keyword: attempting). I also love bug bounty hunting, trekking into the wild, and gaming—because breaking things virtually is just as fun as breaking them in real life. Oh, and I have a soft spot for cats and techno music—so if you ever need security advice set to a killer beat, I’m your guy.

Ready to Elevate Your Security Training?

Empower your teams with the skills they need to secure your applications and stay ahead of the curve.
Get Started Now
X
X
Copyright AppSecEngineer © 2025