T09 · Insecure Skill Coding Practices
- Location
bot/server.js:139- Finding
Unauthenticated Localhost State-Changing API Enables Cross-Origin Strategy Control
- Content
View full analysis
Vulnerability Details
File Location:
bot/server.js:139-151, 164-231
Vulnerability Type: Missing authentication and CSRF protection on state-changing localhost endpoints
Risk Level: MediumVulnerable Code
js const app = express(); app.disable('x-powered-by'); app.use((request, response, next) => { response.setHeader('X-Content-Type-Options', 'nosniff'); response.setHeader('X-Frame-Options', 'DENY'); response.setHeader('Referrer-Policy', 'no-referrer'); response.setHeader( 'Content-Security-Policy', "default-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline'; connect-src 'self'; frame-ancestors 'none'" ); next(); }); app.use(express.json({ limit: '64kb', type: 'application/json' })); app.post('/api/config', (request, response) => { try { memoryConfig = validatePayload(request.body); writePublicConfig(memoryConfig); response.json({ ok: true, credentialsStored: false, paper: true }); } catch (error) { response.status(400).json({ error: error.message }); } }); app.post('/api/strategy/start', async (_request, response) => { if (running) { response.status(409).json({ error: 'Strategy is already running.' }); return; } try { const exchange = createExchange(memoryConfig); running = true; abortState = { aborted: false }; lastActivity = { action: 'starting', at: new Date().toISOString() }; response.status(202).json({ ok: true, paper: true }); strategy .run(exchange, memoryConfig, abortState, (action) => { lastActivity = { action, at: new Date().toISOString() }; }) .catch((error) => { console.error('[Grid] Strategy failed:', error.message); lastActivity = { action: 'error', at: new Date().toISOString() }; }) .finally(() => { running = false; abortStat ...[truncated 3146 chars]- Remediation
View remediation
Remediation Suggestions
- Generate a cryptographically random, per-process authentication token when the server starts.
- Deliver the token only to the trusted local UI and require it in a custom request header on every state-changing endpoint.
- Implement CSRF protection for
/api/config,/api/strategy/start, and/api/strategy/stop. - Validate
Originand, where appropriate,Sec-Fetch-Site, rejecting requests not originating from the exact local UI origin. - Validate the
Hostheader against an explicit allowlist such as127.0.0.1:<configured-port>and reject unexpected hostnames to reduce DNS-rebinding exposure. - Require
Content-Type: application/jsonfor every state-changing endpoint, including start and stop, and reject form-compatible requests. - Require an explicit, short-lived confirmation nonce immediately before starting the strategy.
- Add automated security tests proving that missing tokens, foreign origins, invalid hosts, and form submissions are rejected.
- Retain the existing localhost binding and server-side sandbox enforcement as defense-in-depth controls.
