T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/listener-daemon.mjs:42
- Finding
- Unbounded Persistence of Attacker-Controlled Socket.IO Event Data<![CDATA[ ## Vulnerability Details **File Location**: `scripts/listener-daemon.mjs:42-58` and `scripts/listener.mjs:26-32` **Vulnerability Type**: Unbounded file growth and synchronous processing of untrusted remote data **Risk Level**: Medium ### Vulnerable Code `scripts/listener-daemon.mjs:42-58`: ```js socket.onAny((eventName, ...args) => { 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
- <![CDATA[ ## Remediation Suggestions 1. **Enforce a strict event allowlist and schema** - Process only documented alert event names. - Require `cities` to be an array of bounded strings. - Require `title`, `instructions`, and event names to be strings. - Reject unexpected nested objects and excessive array lengths. 2. **Limit input and record sizes** - Set maximum lengths for every remote string. - Limit the number of cities per alert. - Serialize the validated record and reject it if its byte length exceeds a conservative threshold. 3. **Rate-limit persistence** - Cap accepted events per time window. - Deduplicate repeated alert identifiers or equivalent records. - Drop or aggregate excess events while recording a bounded diagnostic counter. 4. **Use bounded storage** - Implement size- and time-based log rotation. - Configure retention and deletion of old JSONL files. - Place alert files on a dedicated volume with a filesystem quota. - Define a maximum pending-file size and an acknowledgement or truncation process. 5. **Avoid synchronous writes** - Replace `appendFileSync` with asynchronous, backpressure-aware writes. - Use a bounded queue and define an explicit overflow policy. - Ensure write failures are handled without crashing or indefinitely retrying. 6. **Monitor resource thresholds** - Check available disk space before writing. - Stop persistence or enter a degraded mode when storage reaches a defined threshold. - Emit local metrics or alerts for dropped events, oversized records, queue saturation, and write failures. 7. **Harden runtime isolation** - Run the listener as an unprivileged service account. - Restrict filesystem access to a dedicated data directory. - Apply process memory, CPU, and storage limits through the service manager or container runtime. ]]>
