Safety
Why untrusted Markdown cannot execute anything.
Blasdoc treats content as potentially untrusted, because it usually is — a CMS payload, a pull request, a comment box.
Expressions are interpreted
An expression is parsed into an AST and walked by an evaluator that can reach
exactly two things: the context object you passed, and the locals of the current
call. The prototype chain is blocked — constructor, prototype and
__proto__ are refused — so the classic escape of walking from any value to
Function and compiling a string has no path to take.
// Reported as BLASDOC_EXPRESSION_FAILED, never executed:
// <app-button (clicked)="x.constructor.constructor('…')()">There is no new, no arrow function, no await, and no way to name a global.
Raw HTML is filtered
HTML in the content becomes structured IR nodes, filtered through an allow-list
in the core — so every consumer of the IR gets the same guarantee, not just
the Angular renderer. Dangerous tags are dropped with their subtree and
reported; event-handler attributes and javascript: URLs are removed the same
way.
<div>A script tag written here never becomes a script.</div>You can tighten or relax the policy:
provideBlasdoc({
parseOptions: {
htmlPolicy: {
tags: ['div', 'span', 'kbd'],
attributes: { '*': ['class', 'title'] },
},
},
});Components come only from the registry
A tag naming a component you did not register produces a diagnostic and a comment node. There is no path from a string in the content to a class that was not explicitly provided.
The renderer never injects markup
Nodes are created through Angular's Renderer2 — createElement, setAttribute,
appendChild. There is no innerHTML anywhere in the project, including in the
syntax highlighting, which is why highlighting had to produce IR nodes rather
than an HTML string.
What is still yours
Blasdoc protects the rendering path. It cannot protect a context you fill with dangerous functions: anything you put in the context is, by design, callable from the content.
// Don't:
provideBlasdoc({ context: { fetch, localStorage } });