JSX runtime escape
PRISM's compile pass folds JSX into string concatenation.{" "}Attribute values always go through __bextEsc. Text children pass through unchanged — the caller is responsible for escaping. The first column below shows the footgun; the second uses escapeHtml().
Output
| Payload | {raw} | {escapeHtml(raw)} | attribute |
|---|---|---|---|
| plain text | hello world | hello world | |
| HTML chars | strong | <b>strong</b> | |
| image tag | <img src=x> | ||
| ampersand & quotes | Tom & Jerry's "best" episode | Tom & Jerry's "best" episode | |
| attr injection | " onmouseover="x | " onmouseover="x |
Source
// PRISM's escape policy:
// — attributes ALWAYS go through __bextEsc.
// {x}
— children pass through UNCHANGED. Caller's
// responsibility to escape if x might contain HTML.
//
// The compile pass folds {x}
to "" + (x) + "
". To stay
// safe, wrap user-supplied values in escapeHtml() (re-exported from
// the JSX runtime) when they shouldn't be interpreted as HTML.
import { escapeHtml } from "@bext-stack/framework/jsx-runtime";
export default function Page({ user }) {
return (
raw: {user.bio}
{/* dangerous if bio is user input */}
safe: {escapeHtml(user.bio)}
{/* always emits text */}
{/* attributes auto-escaped */}
);
}