-
Notifications
You must be signed in to change notification settings - Fork 252
fix : SSRF IPv6 handling, profile avatar SSRF validation, analysis job null check, and webhook signature-first rate limiting #2467
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
7ed7441
638326a
6fcee5a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,9 +13,33 @@ import * as dns from 'dns/promises'; | |
| * - ::1/128 (IPv6 Loopback) | ||
| * - fc00::/7 (IPv6 Unique Local Addresses) | ||
| * - fe80::/10 (IPv6 Link-local) | ||
| * - ::ffff:0.0.0.0/8 (IPv6-mapped IPv4 private ranges) | ||
| */ | ||
| export function isPrivateIP(ip: string): boolean { | ||
| // IPv4 regex parsing | ||
| // IPv6-mapped IPv4 address: extract the embedded IPv4 and check it. | ||
| // e.g. "::ffff:127.0.0.1" -> check 127.0.0.1 as private IPv4. | ||
| const ipv6MappedMatch = ip.match(/^::ffff:(\d+)\.(\d+)\.(\d+)\.(\d+)$/i); | ||
| if (ipv6MappedMatch) { | ||
| const parts = [ | ||
| parseInt(ipv6MappedMatch[1], 10), | ||
| parseInt(ipv6MappedMatch[2], 10), | ||
| parseInt(ipv6MappedMatch[3], 10), | ||
| parseInt(ipv6MappedMatch[4], 10), | ||
| ]; | ||
|
|
||
| if ( | ||
| parts[0] === 10 || // 10.0.0.0/8 | ||
| (parts[0] === 172 && parts[1] >= 16 && parts[1] <= 31) || // 172.16.0.0/12 | ||
| (parts[0] === 192 && parts[1] === 168) || // 192.168.0.0/16 | ||
| parts[0] === 127 || // 127.0.0.0/8 | ||
| (parts[0] === 169 && parts[1] === 254) || // 169.254.0.0/16 | ||
| parts[0] === 0 // 0.0.0.0/8 | ||
| ) { | ||
| return true; | ||
| } | ||
| } | ||
|
Comment on lines
+21
to
+40
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift Normalize all IPv6-mapped IPv4 forms before checking ranges. Line 21 only matches compressed dotted-decimal 🤖 Prompt for AI Agents |
||
|
|
||
| // Standard IPv4 regex parsing | ||
| const ipv4Match = ip.match(/^(\d+)\.(\d+)\.(\d+)\.(\d+)$/); | ||
| if (ipv4Match) { | ||
| const parts = [ | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Move this validation before any profile-update mutations.
Line 379 can return
400after the earlier Google-account/sessiondeleteManycalls have already committed for email-changing linked accounts. An unsafe avatar URL can therefore partially unlink/invalidate the account while the profile update fails. Run all avatar validation before those DB mutations, or make the whole update flow transactional.🤖 Prompt for AI Agents