fix: clamp SVG rasterization size to prevent memory-exhaustion DoS - #7
Merged
seanghay merged 1 commit intoAug 7, 2026
Merged
Conversation
An SVG can declare an arbitrary intrinsic size via its width/height attributes or viewBox, none of which is bounded by the document's byte length. rasterizeSvg() passed those values straight to MakeSurface(), whose backing store costs width * height * 4 bytes, so a ~100-byte SVG declaring 60000x60000 requested ~14 GB - an untrusted-input DoS for any caller that decodes SVG bytes/URLs (a documented Photo input). Clamp the longest side to 8192 (common GPU max-texture limit), scaling the other axis proportionally so the image still renders correctly, just bounded in resolution. Non-finite or non-positive declared dimensions now fall back to the CSS default replaced-element size instead of reaching MakeSurface. Adds a regression test.
|
@bunlongheng is attempting to deploy a commit to the Seanghay Yath's projects Team on Vercel. A member of the Team first needs to authorize it. |
seanghay
approved these changes
Aug 7, 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.
Following up on #6 (thanks for the quick merge!) with a small defensive hardening fix.
Problem
rasterizeSvg()insrc/skia/image.tsreads an SVG's intrinsic size and passes it straight toMakeSurface():The size comes from the SVG's own
width/heightattributes (orviewBox), none of which is bounded by the document's byte length. Because a raster surface costswidth * height * 4bytes, a tiny document can request an enormous allocation:SVG is a documented
Photoinput and flows throughSoneImage.decode, so any application that renders SVG bytes/URLs from an untrusted source is exposed to a memory-exhaustion denial of service from a ~100-byte payload. This is uncontrolled resource consumption (CWE-400 / CWE-789).Fix
Clamp the longest side to
8192(a common GPU max-texture limit, far above any realistic layout target) and scale the other axis proportionally, so the image still renders correctly - just bounded in resolution. Non-finite or non-positive declared dimensions (malformedwidth/viewBox) now fall back to the CSS default replaced-element size instead of reachingMakeSurface.The change is confined to
rasterizeSvg's sizing; normal SVGs are unaffected.Testing
test/image-svg-dos.test.ts: a 60000x60000 and a 50000x25000 SVG now rasterize within the bound (aspect ratio preserved), while a normal 200x120 SVG is unchanged. The DoS test fails onmain(unbounded allocation / throw) and passes with this fix.No behavior change for legitimately sized documents; purely a bound on adversarial ones.