@@ -1215,6 +1215,25 @@ describe('Image directive', () => {
12151215 ) ;
12161216 } ) ;
12171217
1218+ it ( 'should escape loader output when placeholder is provided as a boolean (security regression)' , ( ) => {
1219+ const maliciousLoader = ( config : ImageLoaderConfig ) => {
1220+ if ( config . isPlaceholder ) {
1221+ return 'https://mysite.com/img.png"); color: red;/*' ;
1222+ }
1223+ return `${ IMG_BASE_URL } /${ config . src } ` ;
1224+ } ;
1225+ setupTestingModule ( { imageLoader : maliciousLoader } ) ;
1226+ const template = '<img ngSrc="path/img.png" width="400" height="300" placeholder="true" />' ;
1227+
1228+ const fixture = createTestComponent ( template ) ;
1229+ fixture . detectChanges ( ) ;
1230+
1231+ const imageDirective = fixture . debugElement . children [ 0 ] . injector . get ( NgOptimizedImage ) ;
1232+ const placeholderValue = ( imageDirective as any ) . generatePlaceholder ( true ) as string ;
1233+
1234+ expect ( placeholderValue ) . toBe ( 'url("https://mysite.com/img.png\\"); color: red;/*")' ) ;
1235+ } ) ;
1236+
12181237 if ( ! isNode ) {
12191238 // DataURLs get stripped from background-image attribute in Node, but not browsers.
12201239 it ( 'should add a background-image tag when placeholder is provided as a data URL' , ( ) => {
@@ -1264,6 +1283,22 @@ describe('Image directive', () => {
12641283 ) ;
12651284 } ) ;
12661285
1286+ it ( 'should prevent CSS injection through placeholder URL values' , ( ) => {
1287+ setupTestingModule ( { imageLoader} ) ;
1288+ const maliciousPlaceholder = 'https://mysite.com/img.png"); color: red;' ;
1289+ const template = `<img ngSrc="path/img.png" width="400" height="300" placeholder='${ maliciousPlaceholder } ' />` ;
1290+
1291+ const fixture = createTestComponent ( template ) ;
1292+ fixture . detectChanges ( ) ;
1293+
1294+ const imageDirective = fixture . debugElement . children [ 0 ] . injector . get ( NgOptimizedImage ) ;
1295+ const placeholderValue = ( imageDirective as any ) . generatePlaceholder (
1296+ maliciousPlaceholder ,
1297+ ) as string ;
1298+
1299+ expect ( placeholderValue ) . toBe ( 'url("https://mysite.com/img.png\\"); color: red;")' ) ;
1300+ } ) ;
1301+
12671302 it ( 'should add a background-image tag when placeholder is provided without value' , ( ) => {
12681303 setupTestingModule ( { imageLoader} ) ;
12691304 const template = '<img ngSrc="path/img.png" width="400" height="300" placeholder />' ;
0 commit comments