forked from mirrors/kingfisher
updated in response to ossf scorecard
This commit is contained in:
parent
411aeefa92
commit
051e4ffdd2
2 changed files with 28 additions and 1 deletions
|
|
@ -3,7 +3,7 @@
|
|||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [v1.91.0]
|
||||
- Added SSRF protection for credential validation: outbound HTTP requests now block connections to loopback, private, link-local, and other non-public IP addresses. Redirect targets are also validated. Use `--allow-internal-ips` to opt out when scanning internal infrastructure.
|
||||
- Added SSRF protection for credential validation: outbound HTTP requests now block connections to loopback, private, link-local, and other non-public IP addresses. Redirects to non-public IP-literal addresses are also blocked. Use `--allow-internal-ips` to opt out when scanning internal infrastructure.
|
||||
- Consolidated JWT SSRF checks to use the shared `is_ssrf_safe_ip` function, covering additional reserved ranges (CGNAT, documentation, benchmarking, IPv6 unique-local).
|
||||
- Removed `ipnet` dependency from `kingfisher-scanner` (no longer needed).
|
||||
- Remediated current RustSec vulnerability findings by upgrading core dependencies including `gix`, `mysql_async`, `axum`, `indicatif`, `quick-xml`, and `console`.
|
||||
|
|
|
|||
|
|
@ -401,6 +401,10 @@ pub fn is_ssrf_safe_ip(ip: &IpAddr) -> bool {
|
|||
match ip {
|
||||
IpAddr::V4(v4) => {
|
||||
let octets = v4.octets();
|
||||
// 0.0.0.0/8 — "This host on this network" (RFC 1122); not routable
|
||||
if octets[0] == 0 {
|
||||
return false;
|
||||
}
|
||||
// Private ranges (RFC 1918)
|
||||
if octets[0] == 10 {
|
||||
return false;
|
||||
|
|
@ -446,6 +450,12 @@ pub fn is_ssrf_safe_ip(ip: &IpAddr) -> bool {
|
|||
return is_ssrf_safe_ip(&IpAddr::V4(mapped));
|
||||
}
|
||||
let segments = v6.segments();
|
||||
// IPv4-compatible IPv6 addresses (::/96, e.g., ::127.0.0.1) are
|
||||
// deprecated (RFC 4291 §2.5.5.1) and can bypass IPv4-only checks.
|
||||
// Reject the entire ::/96 range.
|
||||
if segments[..6].iter().all(|&s| s == 0) {
|
||||
return false;
|
||||
}
|
||||
// Unique local (fc00::/7)
|
||||
if segments[0] & 0xfe00 == 0xfc00 {
|
||||
return false;
|
||||
|
|
@ -507,6 +517,13 @@ mod tests {
|
|||
assert!(!is_ssrf_safe_ip(&IpAddr::V4(Ipv4Addr::UNSPECIFIED)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rejects_ipv4_this_network() {
|
||||
// 0.0.0.0/8 — "This host on this network" (RFC 1122)
|
||||
assert!(!is_ssrf_safe_ip(&IpAddr::V4(Ipv4Addr::new(0, 0, 0, 1))));
|
||||
assert!(!is_ssrf_safe_ip(&IpAddr::V4(Ipv4Addr::new(0, 255, 255, 255))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rejects_ipv4_private_rfc1918() {
|
||||
// 10.0.0.0/8
|
||||
|
|
@ -598,6 +615,16 @@ mod tests {
|
|||
assert!(is_ssrf_safe_ip(&IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x0808, 0x0808))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rejects_ipv4_compatible_ipv6() {
|
||||
// ::127.0.0.1 — deprecated IPv4-compatible IPv6 (loopback)
|
||||
assert!(!is_ssrf_safe_ip(&IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x7f00, 0x0001))));
|
||||
// ::10.0.0.1 — deprecated IPv4-compatible IPv6 (private)
|
||||
assert!(!is_ssrf_safe_ip(&IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x0a00, 0x0001))));
|
||||
// ::8.8.8.8 — even public IPv4 in ::/96 is rejected (deprecated range)
|
||||
assert!(!is_ssrf_safe_ip(&IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x0808, 0x0808))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn accepts_public_ipv4() {
|
||||
assert!(is_ssrf_safe_ip(&IpAddr::V4(Ipv4Addr::new(8, 8, 8, 8))));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue