Add input limits to prevent DoS from untrusted version strings#20
Merged
Add input limits to prevent DoS from untrusted version strings#20
Conversation
Bounds input length and constraint count at parser entry points so malformed or hostile input fails fast instead of consuming unbounded memory or CPU. - Version::MAX_LENGTH (256) caps version strings at construction and cache lookup, bounding cache key memory at entries * MAX_LENGTH - Parser::MAX_INPUT_LENGTH (2048) caps range strings at parse/parse_native - Parser::MAX_CONSTRAINTS (64) caps |-separated and ||-separated constraint counts, preventing the O(n^2 log n) exclusion loop from being driven into multi-second runtime - Narrows bare rescue in maven union parser to ArgumentError so it no longer swallows Interrupt or NoMemoryError Tests in test/test_security.rb cover each limit plus regression checks that legitimate inputs near the limits still parse fast.
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.
Bounds input length and constraint count at parser entry points so malformed or hostile input fails fast instead of consuming unbounded memory or CPU.
The three caches in
Version,Constraint, andParseruse raw input strings as hash keys and evict by entry count, not byte size. An attacker comparing 2000 unique multi-megabyte version strings could pin gigabytes of memory before eviction starts.Version::MAX_LENGTH(256) at construction means oversized input raises before reaching any cache, capping key memory atentries * 256.parse_constraintsrunsexclusions.each { |v| range = range.exclude(v) }where each exclude splits an interval and reconstructs the range with sort and merge. Interval count grows from 1 to N over N exclusions, doing O(N² log N) work. Input likevers:npm/!=1|!=2|...|!=5000ran for several seconds.Parser::MAX_CONSTRAINTS(64) caps the split, and the split itself uses a limit arg so we never materialise thousands of substrings.Parser::MAX_INPUT_LENGTH(2048) atparseandparse_nativebounds total string work before any regex or split runs.The bare
rescuein the maven union parser now catches onlyArgumentError, lettingInterruptandNoMemoryErrorpropagate.Limits sit well above real-world inputs: longest version strings in the wild are Maven snapshots around 60 chars, complex SBOM ranges rarely exceed 20 constraints. Error messages report the offending length but not the string itself to avoid echoing payloads into logs.
test/test_security.rbcovers each limit and asserts that inputs near the limits still parse in well under a second.