T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/encoding_detector.py:38
- Finding
- Unbounded Full-File Read Can Cause Memory Exhaustion## Vulnerability Details **File Location**: `scripts/encoding_detector.py`, lines 38–39 **Vulnerability Type**: Unbounded memory allocation / denial of service **Risk Level**: Medium **Vulnerable Code**: ```python with open(args.file, "rb") as f: size = len(f.read()) ``` ### Technical Analysis The program loads the entire selected file into memory solely to calculate its byte size. This operation has no upper bound. Although `detect_encoding()` limits its initial sample to 10,000 bytes, the subsequent `f.read()` negates that protection. If an attacker can influence the `--file` argument or provide a file that the application processes, they can select a very large readable file. Memory consumption will then scale with the full input size. A special stream-backed path may introduce additional availability risks if reading does not terminate as expected. ### Attack Path 1. An attacker creates, uploads, or identifies a very large file readable by the process. 2. The attacker causes the skill to run with that path through `--file`. 3. Encoding detection reads a bounded 10,000-byte sample. 4. The size calculation calls `f.read()` without a limit and attempts to hold the entire file in memory. 5. The process consumes excessive memory and may be terminated by the operating system, disrupting the agent or hosting service. ### Impact Assessment Successful exploitation can cause denial of service through excessive memory consumption, process termination, degraded host performance, or disruption of concurrent workloads. The flaw does not itself grant additional privileges, execute attacker-controlled code, disclose file contents in output, or cross an access-control boundary. Its scope is limited to files the current process can already open.
- Remediation
- ## Remediation Suggestions Obtain the file size from filesystem metadata instead of reading the content: ```python import os size = os.path.getsize(args.file) ``` For additional hardening: - Use `os.stat()` and `stat.S_ISREG()` to reject devices, FIFOs, sockets, and other non-regular files when they are outside the intended use case. - Apply an explicit maximum accepted file size before processing. - Catch `OSError` and return a controlled error rather than a traceback. - If consistency between detection and reported size matters, open the file once, validate it with `os.fstat(f.fileno())`, and read only the bounded detection sample. - Run the skill with memory and execution-time limits as defense in depth.
