T09 · Insecure Skill Coding Practices
- Location
server.js:11- Finding
Unauthenticated and Unrestricted External API Proxy
- Content
View full analysis
{ try { const zip = req.query.zip; if (!zip) return res.status(400).json({ status: "error", message: "Missing required parameter: zip" }); const start = req.query.start ? parseInt(req.query.start, 10) : 0; const count = req.query.count ? parseInt(req.query.count, 10) : 10; const filter = req.query.filter || "mbdealer"; const resultString = await getMbusaDealers(zip, start, count, filter); const resultJson = JSON.parse(resultString); if (resultJson.status === "error") return res.status(502).json(resultJson); res.status(200).json(resultJson); } catch (error) { console.error("Dealer API Error:", error); res.status(500).json({ status: "error", message: "Internal server error" }); } }); ``` ```js app.get('/api/inventory', async (req, res) => { try { if (!req.query.zip) return res.status(400).json({ status: "error", message: "Missing required parameter: zip" }); // Request parameters are forwarded to an external API. const resultString = await getMbusaInventory(params); const resultJson = JSON.parse(resultString); if (resultJson.status === "error") return res.status(502).json(resultJson); res.status(200).json(resultJson); } catch (error) { console.error("New Inventory API Error:", error); res.status(500).json({ status: "error", message: "Internal server error" }); } }); ``` ```js app.get('/api/used-inventory', async (req, res) => { try { if (!req.query.zip) return res.status(400).json({ status: "error", message: "Missing required par ...[truncated 3121 chars]- Remediation
View remediation
{ console.log(`Server listening on http://${HOST}:${PORT}`); }); ``` 2. **Require authentication** before allowing access in any network-facing deployment. Use securely generated API keys, OAuth, or authentication supplied by a trusted reverse proxy. 3. **Add per-client rate limits and quotas**, for example with a maintained Express rate-limiting middleware. Apply stricter limits to routes that initiate outbound requests. 4. **Limit concurrent upstream operations** with a queue or semaphore so a burst cannot create an unbounded number of pending outbound requests. 5. **Set outbound request deadlines** using `AbortSignal.timeout()` or an `AbortController`: ```js const response = await fetch(apiUrl, { headers, signal: AbortSignal.timeout(10000) }); ``` 6. **Deploy behind a hardened reverse proxy** with connection limits, request timeouts, TLS, authentication, and network access controls. 7. **Document the exposure model clearly** so users do not infer from the localhost examples that the server is technically restricted to localhost. ]]>
