Repository navigation
fix: cap how much an SLA archive may unpack - #59
Merged
Merged
Conversation
SLMetaData read config.json and every thumbnail/ member with no size limit, so a crafted .sl1/.slx deflating a few hundred kB into gigabytes OOM-killed whatever parsed it. A consumer that parses on a queue then crash-loops: the SIGKILL leaves the message unacked and it is redelivered. extract_metadata and extract_thumbnails now go through read_capped, which reads a member with an explicit byte limit. The declared size in the central directory only serves as an early reject; it bounds nothing by itself, because zipfile truncates to it after the decompressor has already produced the data, and the CRC it would be checked against is written by the archive too. Members are read by ZipInfo rather than by name, since a name resolves to the last duplicate, which lets one entry be checked and another read. config.json is capped at 256 kB. Thumbnails share a 4 MB budget across the whole archive, as a per-member cap multiplies by a member count the archive chooses. Real files spend ~3 kB and under 150 kB respectively. A refusal is a ValueError; directory entries under thumbnail/ are skipped instead of yielding an empty thumbnail. The extractors are classmethods so a subclass can override the caps. Calling them on the class or on an instance works as before. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Two failures that arrived without a commit, because every tool is installed with -U and so drifts with time. Ruff's default rule set grew in 0.16.0 to cover UP, SIM, I, RUF, FA and more, and the repo carries no ruff configuration, so it lints against whatever that default happens to be. master passes on 0.15 and reports 41 findings on 0.16 with nothing changed between them. Ruff is pinned to 0.15.*; adopting the wider set is worth doing, but as a reviewed change rather than one that arrives on its own. pytest-pylint declares the pytest_collect_file(path, parent) hook, which pytest 8 removed, so it fails plugin validation before collection starts and both pytest steps exit 3. Its last release is from 2023 and none supports the current hookspec, so the plugin goes and pylint runs as its own step, pinned for the same reason as ruff. 3.3 rather than 4.0 because 4.0 does not install on Python 3.9, which the matrix still covers. The "Lint with pylit" step gains its missing n and splits: pylint now lints both packages, and the pytest run it used to hide inside keeps the type check and doctests over gcode_metadata. flake8 and mypy are installed the same way and carry the same risk; left alone here to keep this to what is currently failing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
sarkafa
force-pushed
the
fix/sla-unpack-budget
branch
from
September 21, 2026 09:03
8c81802 to
99de2c9
Compare
ondratu
approved these changes
Sep 21, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
SLMetaData read config.json and every thumbnail/ member with no size limit, so a crafted .sl1/.slx deflating a few hundred kB into gigabytes OOM-killed whatever parsed it. A consumer that parses on a queue then crash-loops: the SIGKILL leaves the message unacked and it is redelivered.
extract_metadata and extract_thumbnails now go through read_capped, which reads a member with an explicit byte limit. The declared size in the central directory only serves as an early reject; it bounds nothing by itself, because zipfile truncates to it after the decompressor has already produced the data, and the CRC it would be checked against is written by the archive too. Members are read by ZipInfo rather than by name, since a name resolves to the last duplicate, which lets one entry be checked and another read.
config.json is capped at 256 kB. Thumbnails share a 4 MB budget across the whole archive, as a per-member cap multiplies by a member count the archive chooses. Real files spend ~3 kB and under 150 kB respectively. A refusal is a ValueError; directory entries under thumbnail/ are skipped instead of yielding an empty thumbnail.
The extractors are classmethods so a subclass can override the caps. Calling them on the class or on an instance works as before.