Add resource-exhaustion guards for untrusted archives and URLs - #2296
Open
Sash (SashaMIT) wants to merge 2 commits into
Open
Add resource-exhaustion guards for untrusted archives and URLs#2296Sash (SashaMIT) wants to merge 2 commits into
Sash (SashaMIT) wants to merge 2 commits into
Conversation
ZipConverter extracted every archive member into memory with no limits on member count, total uncompressed size, or compression ratio, so a small crafted archive (zip bomb) could exhaust memory and CPU. Add three guards with conservative defaults, each overridable per conversion via keyword arguments: - zip_max_members (default 10000) - zip_max_total_uncompressed_size (default 500 MB), enforced against declared sizes up front and against actual bytes read during chunked extraction - zip_max_compression_ratio (default 100), applied only to members larger than 1 MB to avoid false positives on small compressible files Archives exceeding a limit fail with a FileConversionException.
convert_uri() fetched remote content with no explicit timeout and convert_response() buffered the entire response body with no size cap, so a slow or endless endpoint could hang a conversion indefinitely or exhaust memory. - Pass an explicit timeout to requests (default 30 seconds, overridable via the "timeout" keyword argument) - Cap the buffered response size (default 100 MB, overridable via the "max_response_size" keyword argument), failing fast on oversized Content-Length headers and aborting streaming reads past the limit with a FileConversionException
Author
|
@microsoft-github-policy-service agree |
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.
Problem
When converting untrusted input, two code paths allow unbounded resource consumption:
ZipConverterextracts every archive member into memory with no limits on member count, total uncompressed size, or compression ratio. A small crafted archive (a zip bomb, including nested archives processed recursively) can expand into gigabytes of memory and CPU work.convert_uri()fetches remote content with no explicit timeout, andconvert_response()buffers the entire response body with no size cap. A slow or endless endpoint can hang a conversion indefinitely or stream unbounded data into memory.Changes
ZipConverter guards (
_zip_converter.py), each overridable per conversion via keyword arguments:zip_max_members(default 10000): maximum number of archive memberszip_max_total_uncompressed_size(default 500 MB): enforced against declared sizes up front, and against actual bytes read during chunked extraction, since header sizes in crafted archives cannot be trustedzip_max_compression_ratio(default 100): per-member ratio check, applied only to members larger than 1 MB so small legitimately compressible files are not affectedArchives exceeding a limit fail with a
FileConversionExceptiondescribing the violated limit.URL fetch guards (
_markitdown.py):requests(default 30 seconds, overridable via thetimeoutkeyword argument);requests.Timeoutsurfaces on slow endpointsmax_response_size(default 100 MB, overridable via keyword argument): fast-fail on oversizedContent-Lengthheaders, and streaming reads abort past the limit with aFileConversionExceptionDefaults are conservative but chosen so normal documents are unaffected; the existing
test_files.zipvector and the existing module tests pass unchanged.Tests
New
tests/test_resource_guards.py(11 tests, no live network; HTTP is mocked):session.get; timeout errors surface; oversizedContent-Lengthrejected before streaming; streaming past the limit aborts; a response exactly at the limit still convertsThe guard tests were verified to fail without the source changes (revert-test), and
test_module_vectors.pyplustest_module_misc.pypass.Refs #1514 and #1167.
Made with Cursor