T05 · Unauthorized Access and Privilege Escalation
- Location
- scripts/serve.mjs:65
- Finding
- Unauthenticated Local Portfolio API Exposes Sensitive Financial Data<![CDATA[ ## Vulnerability Details **File Location**: `scripts/serve.mjs:65-91, 113` **Vulnerability Type**: Unauthenticated cross-origin API with non-loopback exposure **Risk Level**: High ### Complete Vulnerable Code ```javascript const server = createServer((req, res) => { const url = new URL(req.url, `http://localhost:${PORT}`); // CORS res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS'); res.setHeader('Access-Control-Allow-Headers', 'Content-Type'); if (req.method === 'OPTIONS') { res.writeHead(204); res.end(); return; } // API: 获取数据 if (url.pathname === '/api/data' && req.method === 'GET') { res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ ok: true, data: loadData() })); return; } // API: 保存数据 if (url.pathname === '/api/data' && req.method === 'POST') { let body = ''; req.on('data', chunk => body += chunk); req.on('end', () => { try { const data = JSON.parse(body); saveData(data); res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ ok: true })); } catch (e) { res.writeHead(400, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ ok: false, error: e.message })); } }); return; } ``` ```javascript server.listen(PORT, () => { console.log(`\n🚀 CryptoFolio 可视化界面已启动`); console.log(`📊 打开浏览器访问: http://localhost:${PORT}`); console.log(`📁 数据文件: ${DATA_FILE}`); console.log(`\n按 Ctrl+C 停止服务器\n`); }); ``` ### Technical Analysis The local HTTP API permits both reading and replacing the complete portfolio without authentication. It also returns `Access-Control-Allow-Origin: *`, authorizes cross-origin `GET`, `POST`, and `OPTIONS` requests, and accepts JSON writes after an unrestricted preflight request. Calling `server.listen(PORT)` without a hostname does not explicit ...[truncated 2127 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Bind the server explicitly to loopback: ```javascript server.listen(PORT, '127.0.0.1', () => { // ... }); ``` 2. Remove wildcard CORS. If cross-origin access is not necessary, do not return CORS headers. Otherwise, validate `Origin` against a strict allowlist. 3. Generate an unpredictable session token when the server starts and require it on every API request. 4. Validate `Host`, `Origin`, and `Sec-Fetch-Site` headers as defense in depth against DNS rebinding and cross-site requests. 5. Validate incoming data against a strict schema. Reject unknown properties, invalid identifiers, unsafe colors, unexpected types, and excessively long strings. 6. Enforce a conservative request-body size limit and terminate oversized requests before parsing. 7. Add safe-write behavior, including temporary-file replacement and backups, to reduce corruption risk. 8. Return appropriate security headers, including a restrictive Content Security Policy, `X-Content-Type-Options: nosniff`, and `Cache-Control: no-store` for API responses. ]]>
