T09 · Insecure Skill Coding Practices
- Location
scripts/listener-daemon.mjs:42- Finding
Unbounded Persistence of Attacker-Controlled Socket.IO Event Data
- Content
View full analysis
{ if (eventName === "connect" || eventName === "disconnect" || eventName === "connect_error") return; for (const alertData of args) { if (!alertData || typeof alertData !== "object") continue; const record = { event: alertData.type || eventName, cities: alertData.cities || [], title: alertData.title || "", instructions: alertData.instructions || "", cityCount: (alertData.cities || []).length, receivedAt: new Date().toISOString() }; const line = JSON.stringify(record); fs.appendFileSync(ALERTS_FILE, line + "\n"); fs.appendFileSync(PENDING_FILE, line + "\n"); console.log(line); } }); ``` `scripts/listener.mjs:26-32`: ```js socket.onAny((event, ...args) => { if (event === "connect" || event === "disconnect") return; for (const alert of args) { const record = { event, ...alert, receivedAt: new Date().toISOString() }; const line = JSON.stringify(record); console.log(line); fs.appendFileSync(ALERTS_FILE, line + "\n"); } }); ``` ### Technical Analysis Both persistent listeners consume events from an external Socket.IO service and append the received content to local JSONL files. Although the daemon performs a basic object-type check, neither implementation enforces: - A maximum event or serialized-record size - Maximum lengths or counts for fields such as `cities`, `title`, and `instructions` - A write-rate limit - A maximum file size or storage quota - Log rotation or retention - Available-disk-space checks - Backpressure or bounded buffering The daemon writes each accepted record to two files using synchronous filesys ...[truncated 2045 chars]- Remediation
View remediation
