useHeadSafe()
The useHeadSafe
composable is a security-focused wrapper around the useHead composable that restricts input to only allow safe values, providing protection against XSS attacks when working with untrusted content.
How It Works
The composable implements a strict whitelist of allowed tags and attributes. When you attempt to use a tag or attribute that isn't on the whitelist, it will be silently ignored to prevent potential security issues.
Security Whitelist
The security whitelist specifies which attributes are allowed for each tag type:
import { useHeadSafe } from 'unhead'
// The whitelist used internally by useHeadSafe
const WhitelistAttributes = {
htmlAttrs: ['class', 'style', 'lang', 'dir'] satisfies (keyof HtmlAttributes)[],
bodyAttrs: ['class', 'style'] satisfies (keyof BodyAttributes)[],
meta: ['name', 'property', 'charset', 'content', 'media'] satisfies (keyof Meta)[],
noscript: ['textContent'] satisfies (Partial<keyof Noscript> | 'textContent')[],
style: ['media', 'textContent', 'nonce', 'title', 'blocking'] satisfies (Partial<keyof Style> | 'textContent')[],
script: ['type', 'textContent', 'nonce', 'blocking'] satisfies (Partial<keyof Script> | 'textContent')[],
link: ['color', 'crossorigin', 'fetchpriority', 'href', 'hreflang', 'imagesrcset', 'imagesizes', 'integrity', 'media', 'referrerpolicy', 'rel', 'sizes', 'type'] satisfies (keyof Link)[],
} as const
Additional Restrictions
- Scripts of any sort are not allowed, except for JSON (
<script type="application/json">
) - usetextContent: myObject
http-equiv
attribute is not allowed on meta tagsdata-*
attributes are allowed on all elements- Link tags will strip invalid href values (like
data:
,javascript:
) - Link tags don't support these rel values:
['stylesheet', 'canonical', 'modulepreload', 'prerender', 'preload', 'prefetch']
API Reference
function useHeadSafe(input: UseHeadInput, options?: HeadEntryOptions): ActiveHeadEntry
The API signature is identical to useHead, but with additional security filtering applied to the input.
Examples
Handling Untrusted Data
When working with head data from an untrusted data source:
import { useHeadSafe } from 'unhead'
// Load metadata from a third-party source
const thirdPartyMeta = loadMeta()
// Safely apply the metadata
useHeadSafe(thirdPartyMeta)
unheadInstance,
User-Generated Content
When allowing users to provide custom meta tags:
import { useHeadSafe } from 'unhead'
// User profile with user-defined metadata
const userProfile = await fetchUserProfile(userId)
useHeadSafe(unheadInstance, {
title: userProfile.pageTitle,
meta: [
{ name: 'description', content: userProfile.pageDescription },
...userProfile.customMetaTags // These will be filtered for safety
]
})
Security Considerations
useHeadSafe
offers protection for most XSS vectors, there are still some important security considerations:Styles
While style attributes are permitted, it's important to note that clickjacking vulnerabilities can still be introduced through malicious CSS. Always validate style content even when using useHeadSafe
.
Best Practices
For maximum security when handling untrusted content:
- Apply additional validation to any user inputs before passing to
useHeadSafe
- Consider using a dedicated content security policy (CSP)
- Use the built-in sanitization but don't rely on it as your only defense
- Avoid allowing custom styles when possible with untrusted content
Common Use Cases
- Working with user-generated content
- Displaying metadata from third-party APIs
- Creating CMS systems where content editors can customize SEO fields
- Implementing white-label solutions where customers can customize branding