@ascentsparksoftware/react-datatables-net wraps DataTables, which renders cell content by writing innerHTML. This
is powerful but means DataTables does not escape cell data by default — unlike JSX, where React
escapes text for you. Untrusted data rendered through DataTables is therefore an XSS sink unless you
take action. This document explains the protections this library provides and their limits.
<DataTablesProvider styling={defaultStyling} escapeByDefault>
<App />
</DataTablesProvider>escapeByDefault (on DataTablesProvider, overridable per table via the <DataTable> prop of the
same name) makes the component append a lowest-priority
{ targets: '_all', render: escapeHtmlRenderer() } to columnDefs. Because DataTables gives
columns[].render (and earlier columnDefs) precedence, only columns without an explicit renderer
are escaped — your custom/orthogonal renderers and defaultContent columns are untouched.
escapeHtmlRenderer() escapes only string values for the display/filter render types
(& < > " '). Numbers, booleans, null/undefined and objects pass through unchanged so numeric
formatting, defaultContent and null-data columns keep working; sort/type values stay raw so
ordering and filtering remain correct.
Recommendation: enable escapeByDefault in every app. Treat it as the default posture.
You can also apply escapeHtmlRenderer() to a single column explicitly:
import { escapeHtmlRenderer } from '@ascentsparksoftware/react-datatables-net';
const columns = [{ data: 'comment', render: escapeHtmlRenderer() }];When a column genuinely needs to render HTML, opt in explicitly. unsafeHtmlRenderer() passes the
given HTML through unchanged for the display type, so it must only ever be fed trusted,
already-sanitized markup — hardcoded strings, or the output of a sanitizer such as
DOMPurify run by you:
import DOMPurify from 'dompurify';
import { unsafeHtmlRenderer } from '@ascentsparksoftware/react-datatables-net';
const columns = [
// You sanitize; the renderer only routes the trusted result to 'display'.
{ data: 'bio', render: unsafeHtmlRenderer((row) => DOMPurify.sanitize(row.bioHtml)) },
];Sort/filter/type still receive the raw underlying data so ordering and search stay correct.
The trust boundary is yours: feeding user-controlled data to unsafeHtmlRenderer() — or writing
your own render that returns raw HTML — is an XSS vulnerability. The function name says "unsafe"
because that trust decision belongs to you.
A column's cell render prop renders through React portals, not through DataTables' HTML path:
const columns: DtColumn<User>[] = [
{ data: 'name', title: 'Name', cell: ({ row }) => <a href={`/user/${row.id}`}>{row.name}</a> },
];React escapes text nodes in JSX, so a cell render prop is safe by construction for untrusted data
(unless you reach for dangerouslySetInnerHTML yourself, which reintroduces the sink). For columns
that need rich display content, prefer cell over string-building render functions.
Edit-in-place controls are real DOM elements (or React components rendered via portals), never
innerHTML, and committed values are written through the DataTables Api
(cell().data(v) + draw(false)), flowing back through the cell's normal display path — which
still honours the escaping renderers above. No edit path introduces an HTML sink. See
Edit in place.
This library itself adds no eval, no Function constructor and no innerHTML — React content
mounts via createPortal, editors are built with createElement, and commits go through the
DataTables Api. It is compatible with a strict script-src CSP (no 'unsafe-eval' needed on our
account).
DataTables, however, assigns innerHTML internally when it renders cells. Under a strict
Content-Security-Policy: require-trusted-types-for 'script', innerHTML assignment is a Trusted
Types sink, so DataTables is not compatible with strict Trusted Types out of the box. Options:
- Do not enable
require-trusted-types-for 'script'for routes that use DataTables, or - Register a permissive Trusted Types policy (e.g. a
defaultpolicy that passes HTML through) and accept that DataTables-injected HTML is not TT-guarded — which is whyescapeByDefaultand the renderers above remain essential.
This is a property of DataTables itself, not of the React wrapper. We document it rather than claim Trusted Types support we cannot honestly provide.
datatables.net(and its transitivejquery),reactandreact-domare peer dependencies — the consuming app owns, dedupes and audits them, so security advisories are resolved in your tree, not pinned by this package.- The DataTables engine is imported lazily in the browser only; it never enters the server module graph of a Next.js app.
- The published package has no runtime dependencies.
Report suspected vulnerabilities privately to the maintainer (Ascentspark) rather than via public issues.