Security¶
miki-template follows Django's security semantics to protect against common web vulnerabilities.
Table of Contents¶
Auto-Escaping¶
All variable output is HTML-escaped by default. This means any <, >, &, ", ', and ` characters in your data are converted to HTML entities before rendering.
If user_input is <script>alert(1)</script>, the output is:
This prevents XSS (Cross-Site Scripting) attacks where malicious users inject executable JavaScript.
Disabling Auto-Escaping¶
Use {% autoescape off %} to disable escaping for a block:
Re-enabling Auto-Escaping¶
Real-world blog post:
<article>
<!-- Post body is trusted CMS content -->
{% autoescape off %}
{{ post.body_html }}
{% endautoescape %}
<!-- User comment is untrusted -->
<div class="comments">
{% for comment in comments %}
<p>{{ comment.text }}</p>
{% endfor %}
</div>
</article>
SafeString¶
Use the safe filter or markSafe() to mark content as trusted (bypassing auto-escaping):
SafeString Class¶
You can also create SafeString instances directly:
Checking if a value is safe¶
HTML Filters¶
safe¶
Mark a string as safe (no escaping):
escape¶
Force HTML escaping, even on SafeString values. This matches Django's {{ value|escape }} semantics:
Real-world: render user-generated content with a safe wrapper
CSRF Protection¶
Use the {% csrf_token %} tag to output a hidden input with the CSRF token:
The token value is HTML-escaped to prevent attribute injection. The output is:
How it works¶
-
The tag looks for
csrf_tokenin the template context. -
If found, it outputs a hidden input with the escaped token value.
-
If not found, it outputs an empty hidden input.
Provide csrf_token in context:
CSP Nonce¶
Use the {% csp_nonce_attr %} tag to output a nonce attribute when csp_nonce is in the context. This is essential for Content-Security-Policy-compliant inline scripts:
If csp_nonce is present in context, the output is:
If csp_nonce is missing, the tag outputs nothing — the <script> tag is rendered without a nonce.
Provide csp_nonce in context:
Path Traversal Protection¶
{% extends %}, {% include %}, and {% extends %} paths are validated to prevent directory traversal attacks:
The engine checks that resolved paths stay within the allowed views directories. An error with message starting with path traversal is thrown if the resolved path escapes the views root.
No Unsafe Code Execution¶
miki-template never uses eval(). Expressions are parsed and evaluated safely using the AST-based expression evaluator. This prevents code injection attacks — template expressions like {{ user.name }} are resolved through property lookups, never by executing arbitrary JavaScript.
HTML Escaping Details¶
miki-template uses the he library for HTML escaping, which converts:
| Character | Escaped |
|-----------|---------|
| & | & |
| < | < |
| > | > |
| " | " |
| ' | ' |
| ` | ` |
// Access escaping directly
const { escapeHtml } = require('miki-template');
// or
import { escapeHtml } from 'miki-template';
const escaped = escapeHtml('<script>alert("xss")</script>');
// → "<script>alert("xss")</script>"
// Force-escape even SafeString values (third argument)
const reescaped = escapeHtml(safeStringInstance, true);
Programmatic Escaping¶
Context Processor Security¶
Context processors run before every render and can inject global variables. Be careful not to expose sensitive data:
Key behavior: Context processor values respect Django semantics — existing context values win over processor defaults. If you render with { user: req.user } and a processor returns { user: 'Guest' }, the explicit req.user is preserved.