Vue / Advanced: architecture, hydration, and production evidence / Lesson 15
Security and untrusted data boundaries
Preserve text, URL, identity, and server trust boundaries while keeping client code free of privileged secrets.
On this page
Lesson goals
- Distinguish safe text rendering from trusted HTML or templates.
- Validate URL and authorization context at the correct layer.
Never turn untrusted content into a Vue template
Vue’s normal text interpolation escapes values for display, while a template is executable application structure. Do not compile user-controlled strings as Vue templates or mount onto untrusted HTML that becomes template source. v-html inserts HTML deliberately and requires a reviewed content policy, often maintained sanitization when rich content is needed. Escaping text, validating a URL, sanitizing HTML, and authorizing data access solve different problems. A framework can provide safe defaults only when the application preserves their intended boundaries. Treat third-party components and content processors as dependencies with their own trust and update requirements.
Use ordinary text rendering for ordinary content
The component displays a message through normal interpolation and does not interpret it as HTML. That is the correct default for a note title or plain message. It does not decide whether the current account may read that message; server-side authorization and data minimization must happen before private information is delivered to the client. Once sensitive content reaches a browser, hiding it with a directive is not a confidentiality boundary. Keep logging and error reporting from collecting the message unnecessarily. The example contains no hostile payload and makes no live request.
<script setup>
const props = defineProps({ message: { type: String, required: true } })
</script>
<template>
<p>{{ props.message }}</p>
</template>
A supplied message such as Notes & references is displayed as text under Vue’s escaping rules. The component performs no rich-HTML insertion, authorization, or persistence. Browser rendering was not executed for this fragment.
Apply a URL policy before binding navigation
Escaping an attribute does not make every URL scheme or destination acceptable. Define allowed protocols, origins, paths, and user-information rules according to the feature, preferably before data reaches the client. The standalone helper below permits only a synthetic HTTPS origin and rejects credentials embedded in a URL. It normalizes relative paths against that origin without contacting it. This is a deliberately narrow policy for the example, not a complete sanitizer or server-side access control. A legitimate-looking link can still lead to unauthorized content unless the destination enforces its own policy.
function allowedNoteUrl(value) {
if (typeof value !== "string") return null
try {
const base = new URL("https://notes.example.invalid/")
const url = new URL(value, base)
if (url.origin !== base.origin || url.protocol !== "https:" || url.username || url.password) return null
return url.href
} catch {
return null
}
}
if (allowedNoteUrl("/read/n1") !== "https://notes.example.invalid/read/n1") {
throw new Error("URL_NORMALIZATION_MISMATCH")
}
if (allowedNoteUrl("https://other.example.invalid/read") !== null) {
throw new Error("URL_ORIGIN_POLICY_MISMATCH")
}
Runs under Node using the URL parser and reserved .invalid example domains. No DNS lookup or request occurs. The assertions check one allowed relative path and one rejected origin, not every possible URL or product policy.
Keep privileged trust off the client
Client bundles, source maps, browser storage, and public environment variables can be inspected by users. Do not place a backend master secret in a Vue source file or assume a build prefix makes it private. Authentication tokens, session cookies, and identity integration need an approved application design; a tutorial store is not a secure credential vault. Protect write operations against the threats relevant to the server session model, including request authenticity where required. Route guards and disabled buttons improve user experience but cannot enforce server permission. Avoid logging private payloads or full credential-bearing URLs during debugging.
Verify the actual boundary and update dependencies
Review raw-output exceptions, URL consumers, component dependencies, server authorization, and state serialization. Test allowed and denied behaviors in an authorized isolated environment and include ordinary legitimate use so a defense does not merely break the feature. Security-related framework updates and advisories need review against the pinned baseline; a green component test cannot establish absence of all vulnerabilities. For SSR, use supported state serialization and never insert untrusted serialized data into HTML through an improvised string concatenation. This course demonstrates benign local parsing only and performs no scanning, exploitation, credential handling, or service changes.
Common errors and fixes
User content is compiled as a template
- Why it happens
- Data is promoted into executable component structure.
- How to fix it
- Render text or use a reviewed rich-content boundary.
- Prevent it next time
- Keep template sources trusted.
An escaped URL points to an unapproved destination
- Why it happens
- Encoding is confused with protocol and destination validation.
- How to fix it
- Apply the feature’s URL policy before binding.
- Prevent it next time
- Test schemes, origins, and malformed input safely.
A build variable exposes a privileged secret
- Why it happens
- Client configuration is mistaken for private server storage.
- How to fix it
- Remove the secret and follow its owner’s exposure-response process.
- Prevent it next time
- Review every client-visible configuration field.
Check your understanding
1. Does hiding a private record with v-if prevent disclosure after it is sent to the browser?
Show worked solution
No. The client already received the data. The server must authorize and minimize what it returns. Visibility is a user-interface choice, not a substitute for the confidentiality boundary.
2. A URL helper accepts the right origin. Does it authorize the destination record?
Show worked solution
No. It supports a narrow navigation policy. The destination still authenticates and authorizes access to the record, and any path restrictions required by the feature need their own explicit checks.
Key takeaways
- Text, HTML, templates, URLs, and permissions have separate boundaries.
- Client code cannot keep privileged server secrets private.
- Use maintained safe APIs and verify their actual scope.