fix(door): block hex IPv4-mapped IPv6 in the SSRF filter (M3)
isBlockedDoorIp blocked the dotted IPv4-mapped form (::ffff:169.254.169.254) but the hex form ::ffff:a9fe:a9fe (=169.254.169.254 IMDS) / ::ffff:7f00:1 (=127.0.0.1) fell through the IPv6 branch and returned false. Decode the hex IPv4-mapped form to dotted IPv4 and run the existing blocked-range checks. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
f337a85682
commit
a3e9b97292
@@ -69,6 +69,15 @@ export function isBlockedDoorIp(ip: string): boolean {
|
||||
let h = ip.trim().toLowerCase().replace(/^\[|\]$/g, '')
|
||||
const mapped = h.match(/^::ffff:(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/)
|
||||
if (mapped) h = mapped[1]
|
||||
// Hex IPv4-mapped form (::ffff:HHHH:HHHH, e.g. ::ffff:a9fe:a9fe == IMDS):
|
||||
// decode the two 16-bit groups to a 32-bit IPv4 and run the same octet
|
||||
// checks below, so it can't slip past the dotted-form guard.
|
||||
const mappedHex = h.match(/^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/)
|
||||
if (mappedHex) {
|
||||
const hi = parseInt(mappedHex[1], 16)
|
||||
const lo = parseInt(mappedHex[2], 16)
|
||||
h = `${hi >> 8}.${hi & 0xff}.${lo >> 8}.${lo & 0xff}`
|
||||
}
|
||||
if (h.includes(':')) {
|
||||
if (h === '::1' || h === '::' || h === '0:0:0:0:0:0:0:0') return true
|
||||
if (h === 'fd00:ec2::254') return true // AWS IPv6 IMDS
|
||||
|
||||
Reference in New Issue
Block a user