@@ -370,7 +370,7 @@ t.test("Blocks IMDS SSRF with untrusted domain", async (t) => {
370370 if ( err instanceof Error ) {
371371 t . same (
372372 err . message ,
373- "Zen has blocked a server-side request forgery: operation(...) originating from unknown source"
373+ "Zen has blocked a stored server-side request forgery: operation(...) originating from unknown source"
374374 ) ;
375375 }
376376 t . same ( address , undefined ) ;
@@ -384,7 +384,7 @@ t.test("Blocks IMDS SSRF with untrusted domain", async (t) => {
384384 if ( err instanceof Error ) {
385385 t . same (
386386 err . message ,
387- "Zen has blocked a server-side request forgery: operation(...) originating from unknown source"
387+ "Zen has blocked a stored server-side request forgery: operation(...) originating from unknown source"
388388 ) ;
389389 }
390390 t . same ( address , undefined ) ;
@@ -524,3 +524,205 @@ t.test("it ignores when the argument is an IP address", async (t) => {
524524 } ) ,
525525 ] ) ;
526526} ) ;
527+
528+ t . test ( "Reports stored SSRF without context" , async ( t ) => {
529+ const api = new ReportingAPIForTesting ( ) ;
530+ const agent = createTestAgent ( {
531+ token : new Token ( "123" ) ,
532+ api,
533+ } ) ;
534+ agent . start ( [ ] ) ;
535+
536+ const wrappedLookup = inspectDNSLookupCalls (
537+ imdsMockLookup ,
538+ agent ,
539+ "http" ,
540+ "request"
541+ ) ;
542+
543+ await new Promise < void > ( ( resolve ) => {
544+ wrappedLookup ( "imds.test.com" , { family : 4 } , ( err , address ) => {
545+ t . same ( err instanceof Error , true ) ;
546+ if ( err instanceof Error ) {
547+ t . same (
548+ err . message ,
549+ "Zen has blocked a stored server-side request forgery: request(...) originating from unknown source"
550+ ) ;
551+ }
552+ t . same ( address , undefined ) ;
553+ resolve ( ) ;
554+ } ) ;
555+ } ) ;
556+
557+ t . match ( api . getEvents ( ) , [
558+ {
559+ type : "started" ,
560+ } ,
561+ {
562+ type : "detected_attack" ,
563+ attack : {
564+ kind : "stored_ssrf" ,
565+ operation : "request" ,
566+ module : "http" ,
567+ blocked : true ,
568+ source : undefined ,
569+ path : "" ,
570+ payload : undefined ,
571+ metadata : {
572+ hostname : "imds.test.com" ,
573+ privateIP : "169.254.169.254" ,
574+ } ,
575+ user : undefined ,
576+ } ,
577+ request : undefined ,
578+ } ,
579+ ] ) ;
580+ } ) ;
581+
582+ t . test ( "Reports stored SSRF with context set" , async ( t ) => {
583+ const api = new ReportingAPIForTesting ( ) ;
584+ const agent = createTestAgent ( {
585+ token : new Token ( "123" ) ,
586+ api,
587+ } ) ;
588+ agent . start ( [ ] ) ;
589+
590+ await runWithContext (
591+ {
592+ remoteAddress : "::1" ,
593+ method : "POST" ,
594+ url : "http://app.example.com:4000" ,
595+ query : { } ,
596+ headers : { } ,
597+ body : {
598+ image : "test.png" ,
599+ } ,
600+ cookies : { } ,
601+ routeParams : { } ,
602+ source : "express" ,
603+ route : "/posts/:id" ,
604+ } ,
605+ async ( ) => {
606+ const wrappedLookup = inspectDNSLookupCalls (
607+ imdsMockLookup ,
608+ agent ,
609+ "http" ,
610+ "request"
611+ ) ;
612+
613+ await new Promise < void > ( ( resolve ) => {
614+ wrappedLookup ( "imds.test.com" , { family : 4 } , ( err , address ) => {
615+ t . same ( err instanceof Error , true ) ;
616+ if ( err instanceof Error ) {
617+ t . same (
618+ err . message ,
619+ "Zen has blocked a stored server-side request forgery: request(...) originating from unknown source"
620+ ) ;
621+ }
622+ t . same ( address , undefined ) ;
623+ resolve ( ) ;
624+ } ) ;
625+ } ) ;
626+ }
627+ ) ;
628+
629+ t . match ( api . getEvents ( ) , [
630+ {
631+ type : "started" ,
632+ } ,
633+ {
634+ type : "detected_attack" ,
635+ attack : {
636+ kind : "stored_ssrf" ,
637+ operation : "request" ,
638+ module : "http" ,
639+ blocked : true ,
640+ source : undefined ,
641+ path : "" ,
642+ payload : undefined ,
643+ metadata : {
644+ hostname : "imds.test.com" ,
645+ privateIP : "169.254.169.254" ,
646+ } ,
647+ user : undefined ,
648+ } ,
649+ request : undefined ,
650+ } ,
651+ ] ) ;
652+ } ) ;
653+
654+ t . test ( "Reports IDMS SSRF from current request context" , async ( t ) => {
655+ const api = new ReportingAPIForTesting ( ) ;
656+ const agent = createTestAgent ( {
657+ token : new Token ( "123" ) ,
658+ api,
659+ } ) ;
660+ agent . start ( [ ] ) ;
661+
662+ await runWithContext (
663+ {
664+ remoteAddress : "::1" ,
665+ method : "POST" ,
666+ url : "http://app.example.com:4000" ,
667+ query : { } ,
668+ headers : { } ,
669+ body : {
670+ image : "https://imds.test.com" ,
671+ } ,
672+ cookies : { } ,
673+ routeParams : { } ,
674+ source : "express" ,
675+ route : "/posts/:id" ,
676+ } ,
677+ async ( ) => {
678+ const wrappedLookup = inspectDNSLookupCalls (
679+ imdsMockLookup ,
680+ agent ,
681+ "http" ,
682+ "request"
683+ ) ;
684+
685+ await new Promise < void > ( ( resolve ) => {
686+ wrappedLookup ( "imds.test.com" , { family : 4 } , ( err , address ) => {
687+ t . same ( err instanceof Error , true ) ;
688+ if ( err instanceof Error ) {
689+ t . same (
690+ err . message ,
691+ "Zen has blocked a server-side request forgery: request(...) originating from body.image"
692+ ) ;
693+ }
694+ t . same ( address , undefined ) ;
695+ resolve ( ) ;
696+ } ) ;
697+ } ) ;
698+ }
699+ ) ;
700+
701+ t . match ( api . getEvents ( ) , [
702+ {
703+ type : "started" ,
704+ } ,
705+ {
706+ type : "detected_attack" ,
707+ attack : {
708+ kind : "ssrf" ,
709+ operation : "request" ,
710+ module : "http" ,
711+ blocked : true ,
712+ source : "body" ,
713+ path : ".image" ,
714+ payload : "https://imds.test.com" ,
715+ metadata : {
716+ hostname : "imds.test.com" ,
717+ privateIP : "169.254.169.254" ,
718+ } ,
719+ user : undefined ,
720+ } ,
721+ request : {
722+ method : "POST" ,
723+ ipAddress : "::1" ,
724+ url : "http://app.example.com:4000" ,
725+ } ,
726+ } ,
727+ ] ) ;
728+ } ) ;
0 commit comments