T09 · Insecure Skill Coding Practices
- Location
scripts/generate_industry_stock_tracker_report.py:100- Finding
Unbounded Remote Response and Attachment Decoding Enables Resource Exhaustion
- Content
View full analysis
Vulnerability Details
File Location:
scripts/generate_industry_stock_tracker_report.py, lines 100–101 and 145–160
Vulnerability Type: Unbounded network response processing and file creation
Risk Level: MediumVulnerable Code
python with urllib.request.urlopen(req, timeout=timeout) as resp: status_code = getattr(resp, "status", None) or resp.getcode() content = resp.read()python def _decode_attachment_base64(data: Dict[str, Any], output_dir: str) -> List[Dict[str, str]]: attachments: List[Dict[str, str]] = [] os.makedirs(output_dir, exist_ok=True) file_map = [ ("wordBase64", "docx", "DOCX"), ("pdfBase64", "pdf", "PDF"), ] article_id = _safe_str(data.get("articleId"), default=uuid.uuid4().hex) safe_article_id = re.sub(r"[^a-zA-Z0-9_-]+", "_", article_id) for key, ext, ftype in file_map: b64_str = _safe_str(data.get(key)) if not b64_str: continue try: raw = base64.b64decode(b64_str) except Exception: continue file_name = "{0}_{1}.{2}".format(safe_article_id, ftype.lower(), ext) file_path = os.path.join(output_dir, file_name) with open(file_path, "wb") as f: f.write(raw)Technical Analysis
The script reads the entire HTTP response into memory without enforcing a maximum response size. It then accepts remotely supplied Base64 attachment fields, decodes each field into another in-memory byte buffer, and writes the result to disk without per-file or aggregate size limits.
A malicious, compromised, or malfunctioning upstream report service can therefore return an exceptionally large response or Base64 attachment. Processing that response may consume memory for the encoded HTTP body, parsed JSON strings, and decoded attachment simultaneously. The resulting file is also written without checking availab ...[truncated 1651 chars]
- Remediation
View remediation
Remediation Suggestions
- Enforce a strict maximum HTTP response size. Read the response incrementally in bounded chunks and abort once the cumulative limit is exceeded.
- Check
Content-Lengthwhen present, while retaining the streaming limit because the header can be absent or untrusted. - Before decoding, estimate the decoded size from the Base64 input length and reject attachments exceeding a defined per-file limit.
- Apply an aggregate limit across all attachments generated by one request.
- Use strict decoding:
python raw = base64.b64decode(b64_str, validate=True) - Avoid retaining unnecessary copies of the full encoded and decoded payloads. Where practical, use incremental Base64 decoding into a size-limited temporary file.
- Check available disk capacity and enforce an application-level storage quota before writing attachments.
- Write through a temporary file with restrictive permissions, then atomically rename it after successful validation. Remove partial files on every failure path.
- Add tests covering oversized HTTP responses, oversized attachments, malformed Base64, low-disk conditions, and cleanup after interrupted writes.
