@@ -196,8 +196,8 @@ impl wasmtime_wasi_http::p2::WasiHttpHooks for PolicyHttpHooks {
196196 // connect, worst case is a second resolution that
197197 // mis-steers — we've still blocked the original
198198 // resolved target.
199- if let Err ( code ) = cidr_precheck ( & cfg, request. uri ( ) , use_tls) . await {
200- return Ok ( Err ( code ) ) ;
199+ if cidr_precheck ( & cfg, request. uri ( ) , use_tls) . await . is_err ( ) {
200+ return Ok ( Err ( P2ErrorCode :: HttpRequestDenied ) ) ;
201201 }
202202 Ok ( wasmtime_wasi_http:: p2:: default_send_request_handler ( request, config) . await )
203203 } ) ;
@@ -207,11 +207,13 @@ impl wasmtime_wasi_http::p2::WasiHttpHooks for PolicyHttpHooks {
207207 }
208208}
209209
210- /// Resolve the request's authority to one or more socket addresses and check
211- /// each against the configured deny CIDRs. Any hit short-circuits the
212- /// request with `HttpRequestDenied`.
213- async fn cidr_precheck ( cfg : & HttpConfig , uri : & Uri , use_tls : bool ) -> Result < ( ) , P2ErrorCode > {
214- // No CIDR deny rules → nothing to do.
210+ /// Resolve the request's authority to one or more socket addresses and
211+ /// check each against configured deny CIDRs. Returns `Err(())` on any deny
212+ /// hit; callers map to their p2/p3 `HttpRequestDenied` error variant.
213+ /// `Ok(())` on no CIDR deny rules at all, missing authority, DNS lookup
214+ /// failure (let the downstream handler surface that with its own
215+ /// diagnostics), or no matching rule.
216+ async fn cidr_precheck ( cfg : & HttpConfig , uri : & Uri , use_tls : bool ) -> Result < ( ) , ( ) > {
215217 if cfg. deny . iter ( ) . all ( |r| r. cidr . is_none ( ) ) {
216218 return Ok ( ( ) ) ;
217219 }
@@ -228,14 +230,12 @@ async fn cidr_precheck(cfg: &HttpConfig, uri: &Uri, use_tls: bool) -> Result<(),
228230 for addr in addrs {
229231 if is_ip_denied_by_cidr ( cfg, addr. ip ( ) , addr. port ( ) ) {
230232 tracing:: warn!( %addr, uri = %uri, "http policy: connect blocked by deny CIDR" ) ;
231- return Err ( P2ErrorCode :: HttpRequestDenied ) ;
233+ return Err ( ( ) ) ;
232234 }
233235 }
234236 Ok ( ( ) )
235237 }
236238 Err ( e) => {
237- // DNS failed — let the downstream handler produce a proper DNS
238- // error with its own diagnostics.
239239 tracing:: debug!( %e, uri = %uri, "http policy: DNS precheck lookup failed; deferring to handler" ) ;
240240 Ok ( ( ) )
241241 }
@@ -272,8 +272,19 @@ impl wasmtime_wasi_http::p3::WasiHttpHooks for PolicyHttpHooks {
272272 Decision :: Allow => {
273273 tracing:: debug!( ?method, %uri, "http policy allow (p3)" ) ;
274274 let _ = fut;
275+ let cfg = self . config . clone ( ) ;
276+ // p3 doesn't expose `use_tls` in RequestOptions; infer from
277+ // the URI scheme (the default handler does the same).
278+ let use_tls = uri. scheme_str ( ) == Some ( "https" ) ;
275279 Box :: new ( async move {
276280 use http_body_util:: BodyExt ;
281+ // DNS + CIDR deny precheck mirrors the p2 path. Closes
282+ // SSRF-by-name for wasip3 HTTP clients (e.g. wasi-fetch).
283+ if cidr_precheck ( & cfg, & uri, use_tls) . await . is_err ( ) {
284+ return Err ( TrappableError :: < P3ErrorCode > :: from (
285+ P3ErrorCode :: HttpRequestDenied ,
286+ ) ) ;
287+ }
277288 let ( res, io) = wasmtime_wasi_http:: p3:: default_send_request ( request, options)
278289 . await
279290 . map_err ( TrappableError :: < P3ErrorCode > :: from) ?;
0 commit comments