@@ -399,6 +399,16 @@ impl NetworkPolicy {
399399 ) ) ;
400400 }
401401
402+ // Block loopback addresses (127.0.0.0/8, ::1) for all policy
403+ // variants. Host-local services typically trust loopback traffic
404+ // and perform no authentication.
405+ if addr. ip ( ) . is_loopback ( ) {
406+ return Err ( anyhow ! (
407+ "network policy denies connection to loopback address {}" ,
408+ addr
409+ ) ) ;
410+ }
411+
402412 match self {
403413 NetworkPolicy :: AllowAll => Ok ( ( ) ) ,
404414 NetworkPolicy :: AllowList ( al) => {
@@ -2922,6 +2932,36 @@ mod tests {
29222932 ) ;
29232933 }
29242934
2935+ #[ test]
2936+ fn net_loopback_blocked ( ) {
2937+ use std:: net:: { Ipv4Addr , Ipv6Addr , SocketAddr } ;
2938+
2939+ let policy = NetworkPolicy :: AllowAll ;
2940+ let lo4 = SocketAddr :: new ( Ipv4Addr :: new ( 127 , 0 , 0 , 1 ) . into ( ) , 80 ) ;
2941+ assert ! (
2942+ policy. check( & lo4) . is_err( ) ,
2943+ "AllowAll must block IPv4 loopback"
2944+ ) ;
2945+
2946+ let lo6 = SocketAddr :: new ( Ipv6Addr :: LOCALHOST . into ( ) , 80 ) ;
2947+ assert ! (
2948+ policy. check( & lo6) . is_err( ) ,
2949+ "AllowAll must block IPv6 loopback"
2950+ ) ;
2951+
2952+ // BlockList should also block loopback
2953+ let bl = BlockList :: from_hosts ( & [ "192.0.2.1" ] ) . unwrap ( ) ;
2954+ let policy = NetworkPolicy :: BlockList ( bl) ;
2955+ assert ! (
2956+ policy. check( & lo4) . is_err( ) ,
2957+ "BlockList must block IPv4 loopback"
2958+ ) ;
2959+ assert ! (
2960+ policy. check( & lo6) . is_err( ) ,
2961+ "BlockList must block IPv6 loopback"
2962+ ) ;
2963+ }
2964+
29252965 #[ test]
29262966 fn net_tools_registered_with_blocklist ( ) {
29272967 let mut tools = ToolRegistry :: new ( ) ;
0 commit comments