@@ -1762,6 +1762,17 @@ func handleStatic(wsToken string) http.HandlerFunc {
17621762 return
17631763 }
17641764 entry , ok := staticFiles [r .URL .Path ]
1765+ if ! ok && strings .HasPrefix (r .URL .Path , "/js/" ) {
1766+ // ES modules under /js/ are served from the embedded ui/js
1767+ // directory. Sanitize to a flat .js file name so path traversal
1768+ // is impossible.
1769+ name := strings .TrimPrefix (r .URL .Path , "/js/" )
1770+ if name != "" && ! strings .Contains (name , ".." ) &&
1771+ ! strings .ContainsAny (name , "/\\ " ) && strings .HasSuffix (name , ".js" ) {
1772+ entry = [2 ]string {"ui/js/" + name , "application/javascript; charset=utf-8" }
1773+ ok = true
1774+ }
1775+ }
17651776 if ! ok {
17661777 http .NotFound (w , r )
17671778 return
@@ -1809,7 +1820,10 @@ func handleStatic(wsToken string) http.HandlerFunc {
18091820 w .Header ().Set ("X-Content-Type-Options" , "nosniff" )
18101821 w .Header ().Set ("Referrer-Policy" , "no-referrer" )
18111822 w .Header ().Set ("X-Frame-Options" , "DENY" )
1812- w .Header ().Set ("Content-Security-Policy" , "frame-ancestors 'none'" )
1823+ // Strict CSP: no inline scripts (all handlers are addEventListener /
1824+ // delegation), styles only from self + the few style="" attributes in
1825+ // index.html. frame-ancestors replaces the old standalone CSP line.
1826+ w .Header ().Set ("Content-Security-Policy" , "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self' ws: wss:; frame-ancestors 'none'; base-uri 'none'; form-action 'none'" )
18131827 w .Write (data )
18141828 }
18151829}
0 commit comments