@@ -44,6 +44,8 @@ describe("noteSecurityWarnings gateway exposure", () => {
4444 let prevHttpsProxyLower : string | undefined ;
4545 let prevAllProxy : string | undefined ;
4646 let prevAllProxyLower : string | undefined ;
47+ let prevNoProxy : string | undefined ;
48+ let prevNoProxyLower : string | undefined ;
4749
4850 beforeEach ( ( ) => {
4951 note . mockClear ( ) ;
@@ -60,6 +62,8 @@ describe("noteSecurityWarnings gateway exposure", () => {
6062 prevHttpsProxyLower = process . env . https_proxy ;
6163 prevAllProxy = process . env . ALL_PROXY ;
6264 prevAllProxyLower = process . env . all_proxy ;
65+ prevNoProxy = process . env . NO_PROXY ;
66+ prevNoProxyLower = process . env . no_proxy ;
6367 delete process . env . OPENCLAW_GATEWAY_TOKEN ;
6468 delete process . env . OPENCLAW_GATEWAY_PASSWORD ;
6569 delete process . env . OPENCLAW_SERVICE_KIND ;
@@ -69,6 +73,8 @@ describe("noteSecurityWarnings gateway exposure", () => {
6973 delete process . env . https_proxy ;
7074 delete process . env . ALL_PROXY ;
7175 delete process . env . all_proxy ;
76+ delete process . env . NO_PROXY ;
77+ delete process . env . no_proxy ;
7278 } ) ;
7379
7480 afterEach ( ( ) => {
@@ -122,6 +128,16 @@ describe("noteSecurityWarnings gateway exposure", () => {
122128 } else {
123129 process . env . all_proxy = prevAllProxyLower ;
124130 }
131+ if ( prevNoProxy === undefined ) {
132+ delete process . env . NO_PROXY ;
133+ } else {
134+ process . env . NO_PROXY = prevNoProxy ;
135+ }
136+ if ( prevNoProxyLower === undefined ) {
137+ delete process . env . no_proxy ;
138+ } else {
139+ process . env . no_proxy = prevNoProxyLower ;
140+ }
125141 } ) ;
126142
127143 const lastMessage = ( ) => String ( note . mock . calls [ note . mock . calls . length - 1 ] ?. [ 0 ] ?? "" ) ;
@@ -377,6 +393,56 @@ describe("noteSecurityWarnings gateway exposure", () => {
377393 expect ( message ) . not . toContain ( "tools.web.fetch.useTrustedEnvProxy is not enabled" ) ;
378394 } ) ;
379395
396+ it ( "does not warn when NO_PROXY=* bypasses every target (#95560)" , async ( ) => {
397+ process . env . HTTP_PROXY = "http://127.0.0.1:7897" ;
398+ process . env . NO_PROXY = "*" ;
399+ const cfg = { } as OpenClawConfig ;
400+ await noteSecurityWarnings ( cfg ) ;
401+ const message = lastMessage ( ) ;
402+ expect ( message ) . not . toContain ( "tools.web.fetch.useTrustedEnvProxy is not enabled" ) ;
403+ expect ( message ) . not . toContain ( "web_fetch will use direct connections" ) ;
404+ } ) ;
405+
406+ it ( "does not warn when lowercase no_proxy=* bypasses every target (#95560)" , async ( ) => {
407+ process . env . HTTP_PROXY = "http://127.0.0.1:7897" ;
408+ process . env . no_proxy = "*" ;
409+ const cfg = { } as OpenClawConfig ;
410+ await noteSecurityWarnings ( cfg ) ;
411+ const message = lastMessage ( ) ;
412+ expect ( message ) . not . toContain ( "tools.web.fetch.useTrustedEnvProxy is not enabled" ) ;
413+ } ) ;
414+
415+ it ( "still warns when a * entry sits inside a NO_PROXY list (matchesNoProxy skips it) (#95560)" , async ( ) => {
416+ process . env . HTTP_PROXY = "http://127.0.0.1:7897" ;
417+ process . env . NO_PROXY = "*,localhost" ;
418+ const cfg = { } as OpenClawConfig ;
419+ await noteSecurityWarnings ( cfg ) ;
420+ const message = lastMessage ( ) ;
421+ expect ( message ) . toContain ( "HTTP_PROXY" ) ;
422+ expect ( message ) . toContain ( "tools.web.fetch.useTrustedEnvProxy" ) ;
423+ } ) ;
424+
425+ it ( "still warns when NO_PROXY only excludes some hosts (#95560)" , async ( ) => {
426+ process . env . HTTP_PROXY = "http://127.0.0.1:7897" ;
427+ process . env . NO_PROXY = "internal.example.com" ;
428+ const cfg = { } as OpenClawConfig ;
429+ await noteSecurityWarnings ( cfg ) ;
430+ const message = lastMessage ( ) ;
431+ expect ( message ) . toContain ( "HTTP_PROXY" ) ;
432+ expect ( message ) . toContain ( "tools.web.fetch.useTrustedEnvProxy" ) ;
433+ } ) ;
434+
435+ it ( "still warns when blank lowercase no_proxy shadows uppercase NO_PROXY=* (#95560)" , async ( ) => {
436+ process . env . HTTP_PROXY = "http://127.0.0.1:7897" ;
437+ process . env . NO_PROXY = "*" ;
438+ process . env . no_proxy = "" ;
439+ const cfg = { } as OpenClawConfig ;
440+ await noteSecurityWarnings ( cfg ) ;
441+ const message = lastMessage ( ) ;
442+ expect ( message ) . toContain ( "HTTP_PROXY" ) ;
443+ expect ( message ) . toContain ( "tools.web.fetch.useTrustedEnvProxy" ) ;
444+ } ) ;
445+
380446 it ( "warns about HTTP_PROXY but omits ALL_PROXY from the env list when both are set (#95560)" , async ( ) => {
381447 process . env . HTTP_PROXY = "http://127.0.0.1:7897" ;
382448 process . env . ALL_PROXY = "socks5://127.0.0.1:7897" ;
0 commit comments