T09 · Insecure Skill Coding Practices
- Location
scripts/recalc.py:88- Finding
Unbounded XLSX Archive Decompression Can Exhaust Memory
- Content
View full analysis
Vulnerability Details
File Location:
scripts/recalc.py, lines 88–90
Vulnerability Type: Uncontrolled resource consumption through unbounded ZIP decompression
Risk Level: MediumVulnerable Code
python with zipfile.ZipFile(filepath, 'r') as zin: file_list = zin.namelist() contents = {name: zin.read(name) for name in file_list}Technical Analysis
XLSX files are ZIP archives. The implementation enumerates every archive member, decompresses each member in full, and retains all resulting data in the
contentsdictionary.No limits are imposed on:
- The number of archive members
- The uncompressed size of an individual member
- The aggregate uncompressed archive size
- The ratio between compressed and uncompressed sizes
Consequently, an attacker-controlled workbook can contain highly compressed data that expands far beyond its on-disk size. Because all expanded members remain resident simultaneously, processing such a workbook can consume all memory available to the Agent process.
Attack Path
- An attacker constructs a syntactically acceptable XLSX archive containing one or more entries with extremely high compression ratios.
- The attacker supplies the workbook for spreadsheet processing.
- The Agent invokes
recalc()as directed by the Skill. - Formula processing reaches
_inject_cached_values(). - The dictionary comprehension calls
zin.read()for every archive member. - The malicious entries expand in memory while all previously expanded entries remain retained.
- The worker runs out of memory, terminates, or destabilizes the host environment.
Impact Assessment
Successful exploitation does not grant additional privileges or provide direct access to confidential data. Its primary effect is denial of service within the privileges of the process running the Skill.
Potential consequences include:
- Termination of the Agent worker through out-of-memory conditions
- Failure or interruption of the cu ...[truncated 263 chars]
- Remediation
View remediation
Remediation Suggestions
Validate the archive before decompressing or parsing its contents:
- Use
ZipFile.infolist()to inspect metadata before reading any member. - Enforce a strict maximum member count.
- Reject members whose declared uncompressed size exceeds a configured per-entry limit.
- Reject archives whose aggregate declared uncompressed size exceeds a configured workbook limit.
- Detect suspicious compression ratios, including entries with very small compressed sizes and disproportionately large uncompressed sizes.
- Stream-copy unchanged archive members instead of loading the complete archive into a dictionary.
- Read entries incrementally with explicit byte limits rather than using unrestricted
zin.read(name). - Run workbook processing in an isolated worker with operating-system memory and CPU limits.
- Treat malformed archives, encrypted entries, duplicate names, and path-traversal-style member names as validation failures.
- Write the modified workbook to a separate temporary file and replace the original atomically only after successful validation and processing.
- Use
