nuxt-og-image: Nuxt OG Image cache poisoning through derivable cache keys on unsigned dynamic image routes
What fixes it
- 6.7.0nuxt-og-image, npmGitHub
npm install nuxt-og-image@6.7.0
A fixed version on one release line is not the upgrade target for every line. Check your exact version and any vendor backports.
Description
Vendor: Nuxt Product: Nuxt OG Image Version: 6.2.5 Description: Due to the specifics of caching and key generation in the Open Graph image cache created by the module, an unauthenticated attacker can modify the content of the image (for example, the title parameter) that is delivered to the user. Impact: Content Spoofing Vulnerable component: route /_og/d/*.png Exploitation conditions: Access to the application Mitigation: Upgrade to 6.7.2 and set a sufficiently secure secret in config ogImage Researcher: Dmitry Vanin (Positive Technologies)
Research
During the previous vulnerability research, it was discovered that version 6.2.5 changed the mechanism for generating cache indexes; it now takes into account the parameters passed during image generation.
However, the image is still generated from data transmitted to the attacker.
_Listing 1. New code for generating indexes in cache_
export function resolvePathCacheKey(e: H3Event, path: string, resolvedOptions?: Record<string, any>) {
const siteConfig = getSiteConfig(e, {
resolveRefs: true,
})
const basePath = withoutTrailingSlash(withoutLeadingSlash(normalizeKey(path)))
const hashParts: any[] = [
basePath,
import.meta.prerender ? '' : siteConfig.url,
]
// Hash resolved options (not raw query string) so unknown/extra query params
// cannot produce unique cache keys and bypass the cache.
if (resolvedOptions)
hashParts.push(hash(resolvedOptions))
return [
(!basePath || basePath === '/') ? 'index' : basePath,
hash(hashParts),
].join(':')
}In this case, basePath is obtained from the _path parameter, resolvedOptions are the normalized settings of the component, for example:
_Listing 2. An example of resolvedOptions_
{"emojis":"noto","extension":"png","width":1200,"height":600,"cacheMaxAgeSeconds":259200,"component":"OgImageDefaultImageTakumi"}From the analysis of resolvedOptions, it was concluded that, in general, all parameters are known either from the direct link to the OG Image or from the server response.
Vulnerability reproduction
- Find the route to OG Image.
_Figure 1. Demonstration of finding the route to OG Image_ <img width="974" height="361" alt="image" src="https://github.com/user-attachments/assets/d3ee6b54-d545-4a3b-8cbf-f82df99ed4d0" />
- Retrieve parameters from the server’s response, especially
cacheMaxAgeSeconds(cache-controlheader,s-maxagekey), the other parameters are known from the meta tags as well as from thec_<component name>parameter.
_Figure 2. Obtaining parameters_ <img width="974" height="245" alt="image" src="https://github.com/user-attachments/assets/84a4cd8b-9281-47ef-b524-0047a0f6077a" />
- Generate a cache key using a script.
_Listing 3. Srcipt_
import {hash} from "ohash";
var url = "https://contoso.com"
var obj = JSON.parse(`{"emojis":"noto","extension":"png","width":1200,"height":600,"cacheMaxAgeSeconds":259200,"component":"OgImageBlogPostTakumi"}`)
var basePath = '/'
var hashParts = [
basePath,
url
]
if (obj)
hashParts.push(hash(obj))
console.log([
(!basePath || basePath === '/') ? 'index' : basePath,
hash(hashParts),
].join(':'))- Repeat the steps as in the vulnerability 1, but transmit the obtained
cacheKeyin addition. - Thus, the same result as in the vulnerability 1 was obtained.
_Figure 4. Server response_ <img width="974" height="729" alt="image" src="https://github.com/user-attachments/assets/5895c0e8-e497-410d-bef9-f6f2f9649261" />
Credits
Researcher: Dmitry Vanin (Positive Technologies)
Text from GitHub Advisory Database
Affected versions 3
- nuxt-og-image, npm>= 6.2.5, < 6.7.0GitHub
- og-imageaffected: >= 6.2.5, < 6.7.0CVE List
- nuxt-og-image, npmfrom 6.2.5, fixed in 6.7.0OSV
References 6
- github.com/nuxt-modules/og-image/commit/e6c5b53ce7f434ab8cbc91298dccfb2b515c56a5Fixvia CVE List
- github.com/nuxt-modules/og-image/releases/tag/v6.7.0Fixvia CVE List
- github.com/nuxt-modules/og-image/security/advisories/GHSA-2x6f-rp82-ppmjAdvisoryvia CVE List
- github.com/advisories/GHSA-2x6f-rp82-ppmjAdvisoryvia GitHub
- nvd.nist.gov/vuln/detail/CVE-2026-102527Referencevia GitHub
- github.com/nuxt-modules/og-image/pull/638Referencevia CVE List