What Causes This Error?
This security error occurs when you try to navigate to a URL with a dangerous protocol like javascript:, data:, or vbscript:. Nuxt blocks these to prevent XSS (Cross-Site Scripting) attacks.
Blocked Protocols
| Protocol | Reason Blocked |
|---|---|
javascript: | Can execute arbitrary code |
data: | Can contain malicious payloads |
vbscript: | Legacy script execution |
Common Scenarios and Fixes
Scenario 1: Accidentally Using javascript: URL
// ❌ Wrong - javascript: protocol
navigateTo('javascript:void(0)')
navigateTo('javascript:alert("hi")')
// ✅ Correct - use function instead
const doSomething = () => {
// Your logic here
}
Scenario 2: Dynamic URL from User Input
// ❌ Dangerous - user could inject javascript:
const userUrl = getUserInput() // Could be 'javascript:alert(1)'
navigateTo(userUrl)
// ✅ Safe - validate URL first
const userUrl = getUserInput()
if (isValidUrl(userUrl)) {
navigateTo(userUrl, { external: true })
}
function isValidUrl(url: string): boolean {
try {
const parsed = new URL(url)
return ['http:', 'https:'].includes(parsed.protocol)
} catch {
return false
}
}
Scenario 3: Links from CMS or Database
// ❌ Dangerous - CMS content could be compromised
const link = cmsContent.link
navigateTo(link)
// ✅ Safe - sanitize and validate
function sanitizeUrl(url: string): string | null {
try {
const parsed = new URL(url)
if (['http:', 'https:', 'mailto:', 'tel:'].includes(parsed.protocol)) {
return url
}
return null
} catch {
// Relative URLs are safe
if (url.startsWith('/') && !url.startsWith('//')) {
return url
}
return null
}
}
const safeUrl = sanitizeUrl(cmsContent.link)
if (safeUrl) {
navigateTo(safeUrl, { external: safeUrl.startsWith('http') })
}
Scenario 4: Data URLs for Downloads
// ❌ Won't work with navigateTo
const dataUrl = 'data:text/plain;base64,SGVsbG8='
navigateTo(dataUrl)
// ✅ Use download approach instead
function downloadFile(content: string, filename: string) {
const blob = new Blob([content], { type: 'text/plain' })
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = filename
a.click()
URL.revokeObjectURL(url)
}
Allowed Protocols
These protocols work with navigateTo:
// ✅ HTTP/HTTPS (with external: true)
navigateTo('https://example.com', { external: true })
// ✅ Relative paths
navigateTo('/about')
navigateTo('/products/123')
// ✅ Internal routes
navigateTo({ name: 'products-id', params: { id: 123 } })
For mailto: and tel: Links
Use regular anchor tags instead of navigateTo:
<template>
<!-- ✅ mailto: links -->
<a href="mailto:hello@example.com">Email Us</a>
<!-- ✅ tel: links -->
<a href="tel:+1234567890">Call Us</a>
</template>
Or with programmatic approach:
// For mailto/tel, use window.location directly
if (process.client) {
window.location.href = 'mailto:hello@example.com'
}
URL Validation Utility
Create a reusable utility for safe navigation:
// utils/navigation.ts
const SAFE_PROTOCOLS = ['http:', 'https:', 'mailto:', 'tel:']
export function safeNavigate(url: string) {
// Handle relative URLs
if (url.startsWith('/') && !url.startsWith('//')) {
return navigateTo(url)
}
// Validate absolute URLs
try {
const parsed = new URL(url)
if (SAFE_PROTOCOLS.includes(parsed.protocol)) {
if (['http:', 'https:'].includes(parsed.protocol)) {
return navigateTo(url, { external: true })
}
// mailto: and tel: need direct approach
if (process.client) {
window.location.href = url
}
} else {
console.warn('Blocked navigation to unsafe URL:', url)
}
} catch (e) {
console.error('Invalid URL:', url)
}
}
Security Best Practices
- Never trust user input - Always validate URLs before navigation
- Whitelist protocols - Only allow known-safe protocols
- Sanitize CMS content - External content could be compromised
- Use CSP headers - Content Security Policy adds extra protection
// nuxt.config.ts - Add CSP headers
export default defineNuxtConfig({
routeRules: {
'/**': {
headers: {
'Content-Security-Policy': "default-src 'self'; script-src 'self'"
}
}
}
})
Quick Checklist
- No
javascript:URLs in navigation calls - User-provided URLs are validated
- CMS/database URLs are sanitized
- Use anchor tags for
mailto:andtel: - External URLs use
{ external: true } - URL validation function in place