nuxt / nuxt

The Intuitive Vue Framework.
https://nuxt.com
MIT License
54.89k stars 5.02k forks source link

Nuxt's innerHTML assignment conflicts with CSP #21052

Open GalacticHypernova opened 1 year ago

GalacticHypernova commented 1 year ago

Environment


Reproduction

https://stackblitz.com/edit/github-rffaxj?file=pages%2Findex.vue

Start from the home page, click on the Nuxt link to Signup, and witness the TrustedHTML conflict.

https://imgur.com/a/SEDfi4V

As I will state in Additional context, since the issue only happens occasionally between certain routes (with this reproduction prompting the error most frequently), I have added a video of the issue happening in action following the steps I provided here for further proof in case it doesn't happen the first time with the stackblitz reproduction.

Describe the bug

When going to some pages, even ones that are completely static with no JavaScript in them, the above content security policy directive will conflict with (I guess?) Nuxt's internal way of setting innerHTML content, causing the page to not update when navigating between certain routes without a page reload.

Additional context

Despite it appearing like a router issue with vue (as it says in the logs that name and route are undefined) it only happens to SOME pages when adding the require-trusted-types-for 'script' directive.

Logs

chunk-LGAZO65B.js:7985  This document requires 'TrustedHTML' assignment.
insertStaticContent @ chunk-LGAZO65B.js:7985
mountStaticNode @ chunk-LGAZO65B.js:5731
patch @ chunk-LGAZO65B.js:5688
mountChildren @ chunk-LGAZO65B.js:5845
mountElement @ chunk-LGAZO65B.js:5777
processElement @ chunk-LGAZO65B.js:5764
patch @ chunk-LGAZO65B.js:5698
componentUpdateFn @ chunk-LGAZO65B.js:6128
run @ chunk-LGAZO65B.js:405
instance.update @ chunk-LGAZO65B.js:6220
setupRenderEffect @ chunk-LGAZO65B.js:6228
mountComponent @ chunk-LGAZO65B.js:6046
processComponent @ chunk-LGAZO65B.js:6011
patch @ chunk-LGAZO65B.js:5700
componentUpdateFn @ chunk-LGAZO65B.js:6128
run @ chunk-LGAZO65B.js:405
instance.update @ chunk-LGAZO65B.js:6220
setupRenderEffect @ chunk-LGAZO65B.js:6228
mountComponent @ chunk-LGAZO65B.js:6046
processComponent @ chunk-LGAZO65B.js:6011
patch @ chunk-LGAZO65B.js:5700
patchSuspense @ chunk-LGAZO65B.js:2513
process @ chunk-LGAZO65B.js:2399
patch @ chunk-LGAZO65B.js:5704
patchKeyedChildren @ chunk-LGAZO65B.js:6305
patchChildren @ chunk-LGAZO65B.js:6265
processFragment @ chunk-LGAZO65B.js:6001
patch @ chunk-LGAZO65B.js:5694
componentUpdateFn @ chunk-LGAZO65B.js:6182
run @ chunk-LGAZO65B.js:405
instance.update @ chunk-LGAZO65B.js:6220
updateComponent @ chunk-LGAZO65B.js:6067
processComponent @ chunk-LGAZO65B.js:6014
patch @ chunk-LGAZO65B.js:5700
componentUpdateFn @ chunk-LGAZO65B.js:6182
run @ chunk-LGAZO65B.js:405
instance.update @ chunk-LGAZO65B.js:6220
callWithErrorHandling @ chunk-LGAZO65B.js:1580
flushJobs @ chunk-LGAZO65B.js:1767
Promise.then (async)
queueFlush @ chunk-LGAZO65B.js:1683
queueJob @ chunk-LGAZO65B.js:1677
(anonymous) @ chunk-LGAZO65B.js:6216
triggerEffect @ chunk-LGAZO65B.js:589
triggerEffects @ chunk-LGAZO65B.js:579
triggerRefValue @ chunk-LGAZO65B.js:1174
(anonymous) @ chunk-LGAZO65B.js:1304
triggerEffect @ chunk-LGAZO65B.js:589
triggerEffects @ chunk-LGAZO65B.js:574
triggerRefValue @ chunk-LGAZO65B.js:1174
(anonymous) @ chunk-LGAZO65B.js:1304
triggerEffect @ chunk-LGAZO65B.js:589
triggerEffects @ chunk-LGAZO65B.js:574
triggerRefValue @ chunk-LGAZO65B.js:1174
(anonymous) @ chunk-LGAZO65B.js:1304
triggerEffect @ chunk-LGAZO65B.js:589
triggerEffects @ chunk-LGAZO65B.js:574
triggerRefValue @ chunk-LGAZO65B.js:1174
(anonymous) @ chunk-LGAZO65B.js:1304
triggerEffect @ chunk-LGAZO65B.js:589
triggerEffects @ chunk-LGAZO65B.js:574
triggerRefValue @ chunk-LGAZO65B.js:1174
set value @ chunk-LGAZO65B.js:1218
finalizeNavigation @ chunk-CSKD2MCS.js:2552
(anonymous) @ chunk-CSKD2MCS.js:2465
Promise.then (async)
pushWithRedirect @ chunk-CSKD2MCS.js:2434
push @ chunk-CSKD2MCS.js:2360
navigate @ chunk-CSKD2MCS.js:1616
callWithErrorHandling @ chunk-LGAZO65B.js:1580
callWithAsyncErrorHandling @ chunk-LGAZO65B.js:1588
invoker @ chunk-LGAZO65B.js:8198

chunk-LGAZO65B.js:1381  [Vue warn]: Unhandled error during execution of scheduler flush. This is likely a Vue internals bug. Please open an issue at https://new-issue.vuejs.org/?repo=vuejs/core 
  at <Chat onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy(Object) {resolveRoute: ƒ, localePath: ƒ, localeRoute: ƒ, localeLocation: ƒ, switchLocalePath: ƒ, …}[[Handler]]: Object[[Target]]: Object[[IsRevoked]]: false > > 
  at <RouteProvider key="/somePage" routeProps= {Component: {…}, route: {…}} pageKey="/somePage"  ... > 
  at <FragmentWrapper > 
  at <RouterView name=undefined route=undefined > 
  at <NuxtPage> 
  at <AsyncComponentWrapper> 
  at <App key=3 > 
  at <NuxtRoot>
warn2 @ chunk-LGAZO65B.js:1381
logError @ chunk-LGAZO65B.js:1633
handleError @ chunk-LGAZO65B.js:1625
callWithErrorHandling @ chunk-LGAZO65B.js:1582
flushJobs @ chunk-LGAZO65B.js:1767
Promise.then (async)
queueFlush @ chunk-LGAZO65B.js:1683
queueJob @ chunk-LGAZO65B.js:1677
(anonymous) @ chunk-LGAZO65B.js:6216
triggerEffect @ chunk-LGAZO65B.js:589
triggerEffects @ chunk-LGAZO65B.js:579
triggerRefValue @ chunk-LGAZO65B.js:1174
(anonymous) @ chunk-LGAZO65B.js:1304
triggerEffect @ chunk-LGAZO65B.js:589
triggerEffects @ chunk-LGAZO65B.js:574
triggerRefValue @ chunk-LGAZO65B.js:1174
(anonymous) @ chunk-LGAZO65B.js:1304
triggerEffect @ chunk-LGAZO65B.js:589
triggerEffects @ chunk-LGAZO65B.js:574
triggerRefValue @ chunk-LGAZO65B.js:1174
(anonymous) @ chunk-LGAZO65B.js:1304
triggerEffect @ chunk-LGAZO65B.js:589
triggerEffects @ chunk-LGAZO65B.js:574
triggerRefValue @ chunk-LGAZO65B.js:1174
(anonymous) @ chunk-LGAZO65B.js:1304
triggerEffect @ chunk-LGAZO65B.js:589
triggerEffects @ chunk-LGAZO65B.js:574
triggerRefValue @ chunk-LGAZO65B.js:1174
set value @ chunk-LGAZO65B.js:1218
finalizeNavigation @ chunk-CSKD2MCS.js:2552
(anonymous) @ chunk-CSKD2MCS.js:2465
Promise.then (async)
pushWithRedirect @ chunk-CSKD2MCS.js:2434
push @ chunk-CSKD2MCS.js:2360
navigate @ chunk-CSKD2MCS.js:1616
callWithErrorHandling @ chunk-LGAZO65B.js:1580
callWithAsyncErrorHandling @ chunk-LGAZO65B.js:1588
invoker @ chunk-LGAZO65B.js:8198

chunk-LGAZO65B.js:7985 Uncaught (in promise) TypeError: Failed to set the 'innerHTML' property on 'Element': This document requires 'TrustedHTML' assignment.
    at insertStaticContent (chunk-LGAZO65B.js:7985:35)
    at mountStaticNode (chunk-LGAZO65B.js:5731:26)
    at patch (chunk-LGAZO65B.js:5688:11)
    at mountChildren (chunk-LGAZO65B.js:5845:7)
    at mountElement (chunk-LGAZO65B.js:5777:7)
    at processElement (chunk-LGAZO65B.js:5764:7)
    at patch (chunk-LGAZO65B.js:5698:11)
    at ReactiveEffect.componentUpdateFn [as fn] (chunk-LGAZO65B.js:6128:11)
    at ReactiveEffect.run (chunk-LGAZO65B.js:405:19)
    at instance.update (chunk-LGAZO65B.js:6220:52)
insertStaticContent @ chunk-LGAZO65B.js:7985
mountStaticNode @ chunk-L
danielroe commented 1 year ago

Nice spot. Would you be able to provide a reproduction? 🙏

GalacticHypernova commented 1 year ago

Thank you! As I mentioned, the reproduction is having that directive in your content security policy, that's really all that is needed to recreate the issue. If need be, I can share my project privately where I tested it, but the content of the page does not really matter from what I checked. Even if it's just a generic rules page and is completely static it still (in my case) conflicts and errors out. (The reason I would like to share it privately in case necessary is it's a personal project of mine for an upcoming thing which I don't feel comfortable sharing publicly)

GalacticHypernova commented 1 year ago

Also, I just found out I forgot to update. I thought maybe it was a 3.4.3 issue but 3.5.1 is also affected, so I will just update the environment. Just wanted to let you know why it would look different when you check this again. @danielroe

Hebilicious commented 1 year ago

Might be related : https://github.com/vitejs/vite/issues/10553

GalacticHypernova commented 1 year ago

@Hebilicious it might, but as far as I'm aware I didn't see that it was from vite, unlike my newer CSP conflict issue nuxt/nuxt#21268 where it specifically errored on vite's end. However I can try to see if this one is also related to it because as I mentioned, this doesn't even happen every single time.

danielroe commented 1 year ago

Indeed, I believe this is likely coming from vite (though it's possible it's from vue). You can try using the webpack builder to see if the issue is replicable without vite or https://stackblitz.com/github/nuxt-contrib/vue3-ssr-starter to see if it is replicable without nuxt.

GalacticHypernova commented 1 year ago

Yea I was planning on doing it. just got a little busy with personal life. I'll get around to it soon though and post any update in case anything comes up, because so far it was only showing Nuxt errors.

GalacticHypernova commented 1 year ago

@danielroe I have tested it with the vue3-ssr-starter, same error is prompted, so it's either a vite or a vue issue. And although this question may sound silly, how do I choose to use webpack in stead of vite?

Hebilicious commented 1 year ago

@GalacticHypernova In your config, change the builder to "@nuxt/webpack-builder" https://nuxt.com/docs/api/configuration/nuxt-config#builder

GalacticHypernova commented 1 year ago

@Hebilicious thanks! Will check it out when I get home

dargmuesli commented 6 months ago

Vite trusted type support is underway: https://github.com/vuejs/core/pull/10844

dargmuesli commented 3 months ago

The PR I mentioned in the previous comment has been merged. I suppose the feature will be part of the upcoming Vue version 3.5.0.