chore: upgrade to 15.15.4-exodus.0 for RN 0.85#14
Open
Conversation
- Object.setPrototypeOf(tags, null) to prevent prototype pollution via tag names - Object.create(null) for parsed props and style objects - Log unknown SVG tags instead of silently returning null
Add propWhitelist Set with all known safe SVG props. Apply sanitizeProps() to SvgAst root props, astToReact child props, and SvgUri override props. Unknown props are logged and stripped to prevent prop injection attacks.
Validate SVG XML source with @exodus/svg-safe before parsing. On validation failure, log error and return null instead of parsing potentially malicious SVG content.
Replace permissive /#([^)]+)'\''?\)?$/ with strict anchored pattern /^(?:url\()?#([a-zA-Z0-9\-_]+)\)?$/ that only matches valid SVG ID references (url(#id) or #id with alphanumeric/dash/underscore chars).
Strip mHref values from UseView FLog.w messages and mClipPath/mClipRule from VirtualView FLog.w messages to prevent log injection.
Rename package, update repository URLs to ExodusForks, set publishConfig to restricted, version 15.15.4-exodus.0, remove upstream CI workflows and issue templates.
| // Bezier Curve Approximation | ||
| float arc = ea - sa; | ||
| if (arc < 0 && clockwise) { | ||
| arc += Math.PI * 2; |
| return JSON.parse(data); | ||
| } else { | ||
| const emptyObject = {}; | ||
| fs.writeFileSync(filePath, JSON.stringify(emptyObject, null, 2), 'utf8'); |
Comment on lines
+7
to
+9
| return (polyPoints as string) | ||
| .replace(/[^eE]-/, ' -') | ||
| .split(/(?:\s+|\s*,\s*)/g) |
| if (typeof universal === 'number') { | ||
| x = y = universal; | ||
| } else if (typeof universal === 'string') { | ||
| const coords = universal.split(/\s*,\s*/); |
| const beforeExec = /(^|\n).*$/.exec(before); | ||
| const beforeLine = (beforeExec && beforeExec[0]) || ''; | ||
| const after = source.slice(i); | ||
| const afterExec = /.*(\n|$)/.exec(after); |
|
|
||
| function exec(command) { | ||
| console.log(`[${ERROR_PREFIX}]> ` + command); | ||
| execSync(command); |
| fileName !== undefined ? `${spotlessApply} ${fileArgument}` : spotlessApply; | ||
|
|
||
| // reformat code | ||
| execSync(command, writeToConsoleOnError); |
| // file passed by lint-staged is now reformatted | ||
| if (fileName !== undefined) { | ||
| // so stage this file again after formatting | ||
| execSync(`git add ${fileName}`, writeToConsoleOnError); |
| const FILTERS_DIR = path.resolve(ROOT_DIR, 'apple/Filters/MetalCI'); | ||
|
|
||
| function exec(command) { | ||
| execSync(command); |
… __tests__, screenshots, windows) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace /(?:\s+|\s*,\s*)/g (overlapping alternation vulnerable to catastrophic backtracking on repeated whitespace) with /[\s,]+/ split plus filter(Boolean). Single character class, no alternation, no nested quantifiers. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace /\s*,\s*/ regex split with split(',').map(s => s.trim()) —
no regex at all. Eliminates potential backtracking on whitespace-heavy
input while producing identical results.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace /(^|\n).*$/ and /.*(\n|$)/ in locate() with pure string operations (lastIndexOf/indexOf + slice). Zero regex, zero backtracking risk in the security-sensitive SVG XML parser path. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… cast Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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.
Summary
Major version rebase of Exodus security patches onto upstream react-native-svg v15.15.4 (from ~v9.8.x).
The Exodus patches focus heavily on SVG parsing security: prop whitelisting, null-prototype hardening,
regex hardening, and svg-safe validation integration.
Part of the RN 0.85 upgrade: ExodusMovement/exodus-mobile#38221.
Exodus Patches
a8a53a88f53a90d61a76d0c6680324e23d64f48594838542Fork Cleanup
Removed non-shipped directories to eliminate Copilot/CodeQL scan noise and reduce repo size (635 files, 147,347 lines deleted):
.github/apps/(14 MB)e2e/__tests__/screenshots/windows/scripts/*(exceptrnsvg_utils.rb)codegen-*.js,format-java.js,metal.js) — not shipped; triggered Copilot findingsKept:
scripts/rnsvg_utils.rb— referenced byRNSVG.podspecand listed inpackage.jsonfilesfield.Also removed
windowsfrompackage.jsonfilesfield since the directory was deleted.Verified: Build-critical files intact:
RNSVG.podspec,android/build.gradle,android/src/main/jni/CMakeLists.txt,package.json,scripts/rnsvg_utils.rb.ReDoS Security Fixes
3 additional commits hardening shipped code against Regular Expression Denial of Service:
extractPolyPoints.ts— split regexBefore:
/(?:\s+|\s*,\s*)/g— overlapping alternation where\s+and\s*,\s*both match whitespace, causing catastrophic backtracking on repeated\tcharacters.After:
.split(/[\s,]+/).filter(Boolean)— single character class with no alternation or nested quantifiers.extractTransform.ts— comma splitBefore:
/\s*,\s*/—\s*quantifiers around literal comma, flagged for backtracking risk on whitespace-heavy input.After:
.split(',').map((s) => s.trim())— no regex at all. Splits on literal comma, trims each result.xml.tsx— locate() line extractionBefore:
/(^|\n).*$/and/.*(\n|$)/in thelocate()error-reporting function —.*with alternation anchors creates backtracking on long lines.After: Pure string operations using
lastIndexOf('\n')+sliceandindexOf('\n')+slice. Zero regex in the security-sensitive XML parser path.Note: The existing Exodus patch at
1a76d0c6(idPattern hardening) only modifiedsrc/lib/util.ts, notsrc/xml.tsx, so the xml.tsx fix was still needed.Remaining accepted finding:
PathParser.javadouble→float narrowing — upstream Java code, standard graphics precision behavior (Android Canvas APIs use float). No fix needed.Upstream Changelog (~v9.8.x → v15.15.4)
~860 commits across 6 major versions. Key changes:
getBBox/getCTM/getScreenCTMAPIs; CSS inline stylescontext-fill/context-stroke;strokeDasharraywith AnimatedcodegenNativeComponentadoption; color processing moved to native sideFeGaussianBlur,FeColorMatrix,FeBlend,FeFlood,FeMerge,FeOffset,FeComposite,FeDropShadow); CSS variable support;maskUnits/mask-type; 16 KB page size for Android; memory leak fixesRCTImageon iOS;bufferdep removed in favor ofatobfor base64 decoding; shadow node metrics removed (revert); macOS build fixesSecurity Audit of Upstream Changes
Prototype Pollution Vectors
Upstream v15 baseline: The
tagsobject insrc/xml.tsxwas a plain{ [tag: string]: ComponentType }dict and parsed props were initialized with{}— both open to prototype pollution if an attacker could inject__proto__orconstructoras an SVG tag name or attribute.Upstream v15.0.0→v15.15.4: No upstream mitigations added. The
tagsdict was refactored intosrc/xmlTags.ts(typedas const), which narrows the type but does not set a null prototype.Exodus patches address this:
94838542appliesObject.setPrototypeOf(tags, null)and changes all prop/style object literals toObject.create(null). This is correct and complete for the JS parsing layer. ✅ Mitigated.Command Injection
No
exec,spawn,child_process, or shell invocations in the runtime library source (src/). Native layers use only Android SDK drawing APIs and Apple CoreGraphics — no subprocess execution. ✅ Clean.Network Requests
src/utils/fetchData.tsmakes afetch()call infetchUriData()when a URI is passed toSvgUri— expected behavior for a URI-based SVG loader. The URI is app-supplied (not from parsed SVG content). The@exodus/svg-safevalidation gate runs before parsing.Notable improvement:
v15.15.3removed thebuffernpm dependency in favor ofatob()for base64 data-URI decoding, eliminating a transitive Node.js polyfill dependency. ✅ Acceptable.Binary Blobs / Non-reproducible Artifacts
Three PEG-generated parser files are checked-in generated artifacts from
pegjs/peggy, reproducible from.pegsource files in the repo. No prebuilt native blobs found insrc/. ✅ Clean.ReDoS Patterns
The old
idPatternregex/#([^)]+)'?\)?$/was an unbounded character class with no anchoring — a ReDoS candidate on crafted inputs. Exodus patch1a76d0c6replaces it with/^(?:url\()?#([a-zA-Z0-9\-_]+)\)?$/, which is fully anchored, uses a strict character class, and has no backtracking ambiguity.Other regexes audited:
validNameCharacters,whitespace,RGB_RGBA_PATTERN,fontRegExp— all safe patterns with no user-controlled repetition. Nonew RegExp(userInput)patterns found. ✅ Mitigated.Unsafe Dynamic Code Execution
No
eval(),new Function(), orFunction(string)calls insrc/. PEG parsers use statically compiled rule functions, not dynamic code evaluation. ✅ Clean.New Dependencies
warn-once@0.1.1@exodus/svg-safecss-select@^5.1.0SvgCss; no networkcss-tree@^1.1.3Findings Summary
fetch()is app-URI-driven;bufferdep removed;@exodus/svg-safevalidates before parsingidPatternreplaced with strict anchored pattern by Exodus patch; 3 additional ReDoS fixes appliedwarn-onceis benign;@exodus/svg-safeis a security addition>— no external entity expansion (custom parser has no XML entity resolver)Test Plan
src/package.jsonin exodus-mobile-upgrade worktreeyarn ios:basebuildsyarn android:basebuildsSvgXmlwith DOCTYPE-bearing SVG content does not crash