@@ -88,7 +88,7 @@ Deno.test("CSP - GET report only", async () => {
8888 ) ;
8989} ) ;
9090
91- Deno . test ( "CSP - useNonce replaces unsafe-inline with nonce " , async ( ) => {
91+ Deno . test ( "CSP - useNonce appends nonce alongside unsafe-inline" , async ( ) => {
9292 const app = new App ( )
9393 . use ( csp ( { useNonce : true } ) )
9494 . get ( "/" , ( ctx ) => {
@@ -109,10 +109,14 @@ Deno.test("CSP - useNonce replaces unsafe-inline with nonce", async () => {
109109 const html = await res . text ( ) ;
110110 const cspHeader = res . headers . get ( "Content-Security-Policy" ) ! ;
111111
112- // Should contain nonce directive, not unsafe-inline
113- expect ( cspHeader ) . not . toContain ( "'unsafe-inline'" ) ;
114- expect ( cspHeader ) . toMatch ( / s c r i p t - s r c ' s e l f ' ' n o n c e - [ a - f 0 - 9 ] + ' / ) ;
115- expect ( cspHeader ) . toMatch ( / s t y l e - s r c ' s e l f ' ' n o n c e - [ a - f 0 - 9 ] + ' / ) ;
112+ // Should contain both unsafe-inline and nonce
113+ expect ( cspHeader ) . toContain ( "'unsafe-inline'" ) ;
114+ expect ( cspHeader ) . toMatch (
115+ / s c r i p t - s r c ' s e l f ' ' u n s a f e - i n l i n e ' ' n o n c e - [ a - f 0 - 9 ] + ' / ,
116+ ) ;
117+ expect ( cspHeader ) . toMatch (
118+ / s t y l e - s r c ' s e l f ' ' u n s a f e - i n l i n e ' ' n o n c e - [ a - f 0 - 9 ] + ' / ,
119+ ) ;
116120
117121 // Nonce should not leak as a response header
118122 expect ( res . headers . get ( "X-Fresh-Nonce" ) ) . toBeNull ( ) ;
@@ -237,7 +241,7 @@ Deno.test("CSP - nonce does not leak as header without CSP middleware", async ()
237241 expect ( ( res as any ) [ NONCE_SYMBOL ] ) . toBeDefined ( ) ;
238242} ) ;
239243
240- Deno . test ( "CSP - useNonce replaces unsafe-inline in default-src" , async ( ) => {
244+ Deno . test ( "CSP - useNonce appends nonce alongside unsafe-inline in default-src" , async ( ) => {
241245 const app = new App ( )
242246 . use ( csp ( {
243247 useNonce : true ,
@@ -257,6 +261,44 @@ Deno.test("CSP - useNonce replaces unsafe-inline in default-src", async () => {
257261 await res . body ?. cancel ( ) ;
258262 const cspHeader = res . headers . get ( "Content-Security-Policy" ) ! ;
259263
260- // default-src should have nonce, not unsafe-inline
261- expect ( cspHeader ) . toMatch ( / d e f a u l t - s r c ' s e l f ' ' n o n c e - [ a - f 0 - 9 ] + ' / ) ;
264+ // default-src should contain both unsafe-inline and nonce
265+ expect ( cspHeader ) . toMatch (
266+ / d e f a u l t - s r c ' s e l f ' ' u n s a f e - i n l i n e ' ' n o n c e - [ a - f 0 - 9 ] + ' / ,
267+ ) ;
268+ } ) ;
269+
270+ Deno . test ( "CSP - nonce only added when unsafe-inline is present in directive" , async ( ) => {
271+ const app = new App ( )
272+ . use ( csp ( {
273+ useNonce : true ,
274+ csp : [ "script-src 'self'" ] ,
275+ } ) )
276+ . get ( "/" , ( ctx ) => {
277+ return ctx . render (
278+ < html >
279+ < head />
280+ < body > hello</ body >
281+ </ html > ,
282+ ) ;
283+ } ) ;
284+
285+ const server = new FakeServer ( app . handler ( ) ) ;
286+ const res = await server . get ( "/" ) ;
287+ await res . body ?. cancel ( ) ;
288+ const cspHeader = res . headers . get ( "Content-Security-Policy" ) ! ;
289+
290+ // script-src (user override, no 'unsafe-inline'): no nonce, no unsafe-inline
291+ const scriptSrc = cspHeader . split ( "; " ) . find ( ( d ) =>
292+ d . startsWith ( "script-src" )
293+ ) ! ;
294+ expect ( scriptSrc ) . toEqual ( "script-src 'self'" ) ;
295+ expect ( scriptSrc ) . not . toContain ( "'unsafe-inline'" ) ;
296+ expect ( scriptSrc ) . not . toMatch ( / ' n o n c e - / ) ;
297+
298+ // style-src (default, has 'unsafe-inline'): nonce appended alongside
299+ const styleSrc = cspHeader . split ( "; " ) . find ( ( d ) =>
300+ d . startsWith ( "style-src" )
301+ ) ! ;
302+ expect ( styleSrc ) . toContain ( "'unsafe-inline'" ) ;
303+ expect ( styleSrc ) . toMatch ( / ' n o n c e - [ a - f 0 - 9 ] + ' / ) ;
262304} ) ;
0 commit comments