Hacktricks-skills xss-sniff-leak

How to leak script content using MIME type sniffing vulnerabilities. Use this skill whenever the user mentions XSS, content sniffing, X-Content-Type-Options, leaking JavaScript files, MIME type attacks, or needs to extract script content from a target. Trigger for any web security testing involving script disclosure, even if the user doesn't explicitly mention 'sniffing' or 'MIME type'.

install
source · Clone the upstream repo
git clone https://github.com/abelrguezr/hacktricks-skills
manifest: skills/pentesting-web/xss-cross-site-scripting/sniff-leak/SKILL.MD
source content

XSS Sniff Leak Techniques

This skill covers techniques to leak script content by exploiting missing

X-Content-Type-Options: nosniff
headers. When this header is absent, browsers may attempt to "sniff" the content type, which can be abused to extract sensitive JavaScript files.

Background: MIME Type Sniffing

When a server doesn't send

X-Content-Type-Options: nosniff
, browsers may ignore the declared
Content-Type
header and attempt to determine the actual content type by examining the file's bytes. This behavior can be exploited to read files that should be protected.

Technique 1: UTF-16 Conversion Attack

Concept

Add specific bytes at the beginning of a request that make the browser interpret the response as UTF-16 encoded JavaScript. This can cause the browser to execute the content as a script even when it's served as

text/plain
.

How it works

  1. The target serves a file (e.g., a script) with
    Content-Type: text/plain
  2. The file lacks
    X-Content-Type-Options: nosniff
  3. By prepending certain bytes, you can trick the browser into treating the content as UTF-16 encoded JavaScript
  4. The browser executes the script, potentially leaking its contents

Example payload structure

<script src="[target-script-url]" charset="utf-16"></script>

Or with byte manipulation to force UTF-16 interpretation:

<script>
  fetch('[target-script-url]').then(r => r.text()).then(t => console.log(t));
</script>

When to use

  • Target serves JavaScript files with incorrect or missing Content-Type headers
  • X-Content-Type-Options: nosniff
    is not present
  • You need to extract the contents of a script file

Technique 2: ICO Image Treatment Attack

Concept

Load the script file as if it were an ICO image and access image properties (like

width
) to trigger the browser to process and potentially expose the content.

How it works

  1. Create an
    <img>
    tag pointing to the script file URL
  2. Access the
    width
    or
    height
    property of the image element
  3. The browser attempts to parse the script as an image, which can leak information

Example implementation

<img id="leak" src="[target-script-url]" onload="console.log(this.width)">

Or with JavaScript:

const img = new Image();
img.src = '[target-script-url]';
img.onload = () => {
  console.log('Width:', img.width);
  console.log('Height:', img.height);
};

When to use

  • Target serves files without proper Content-Type headers
  • You want to verify if sniffing is possible
  • Alternative when UTF-16 technique doesn't work

Practical Testing Workflow

Step 1: Check for vulnerability

# Check headers
curl -I https://target.com/path/to/script.js

# Look for:
# - Content-Type: text/plain (or incorrect type)
# - Missing X-Content-Type-Options: nosniff

Step 2: Test UTF-16 technique

Create a test page:

<!DOCTYPE html>
<html>
<head><title>Sniff Test</title></head>
<body>
  <h1>UTF-16 Sniff Test</h1>
  <script>
    fetch('https://target.com/path/to/script.js')
      .then(r => r.text())
      .then(t => {
        document.write('<pre>' + escape(t) + '</pre>');
      });
  </script>
</body>
</html>

Step 3: Test ICO technique

<!DOCTYPE html>
<html>
<head><title>ICO Sniff Test</title></head>
<body>
  <h1>ICO Sniff Test</h1>
  <img id="leak" src="https://target.com/path/to/script.js" onload="alert('Loaded: ' + this.width + 'x' + this.height)">
</body>
</html>

Detection and Mitigation

How to detect

  1. Check for missing
    X-Content-Type-Options: nosniff
    header
  2. Verify Content-Type headers match actual content
  3. Test with the techniques above in a controlled environment

How to fix (for defenders)

# Nginx example
add_header X-Content-Type-Options "nosniff" always;
# Apache example
Header always set X-Content-Type-Options "nosniff"
# Python/Flask example
@app.after_request
def add_security_headers(response):
    response.headers['X-Content-Type-Options'] = 'nosniff'
    return response

References

Important Notes

  • Only use these techniques on systems you have explicit authorization to test
  • These are legitimate security research techniques for penetration testing
  • Always document findings and provide remediation guidance
  • Modern browsers are increasingly resistant to these attacks, but legacy systems may still be vulnerable