Bug Issue 1561 cfieldsView Stored XSS - sebiboga/testlink-upgraded GitHub Wiki
The modern Custom Fields screen (gui/templates/cfields/cfieldsView.html) rendered
custom-field Name and Label column cells with DataTables, which writes cell
data via html(). A custom field whose name/label contains markup (e.g. "> <img src=x onerror=alert(73)>) executed the handler on load. The row Actions cell's inline onclick="deleteCf(id,'name')" only escaped single quotes, so a " in the name broke out of the attribute (stored XSS; any user with cfield_management can seed it — every reader of the list is affected).
-
DataTables cells —
renderTable()(cfieldsView.html:198-230) pushedcf.label/cf.nameunescaped into DataTables row data; DataTables writes cells viahtml(). Legacy templatecfieldsView.tpl:58-59used Smarty|escape— lost in the Dashio rewrite. -
Delete action attribute — inline
onclick="deleteCf(id,'<name>')"escaped only single quotes → a"broke out of the attribute. -
Server accepts markup by design (
api/cfields/index.php:134-135TRIM-only — legacy parity). XSS is prevented at render time, not by scrubbing stored labels.
-
Landed with task #950 (
b7aaee02e): newescAttr(), applied to the label/name/type cells (cfieldsView.html:213-215); delete icon moved todata-delete-id/data-delete-name(escaped) + delegated$(document).on('click', '.action-btn.danger[data-delete-id]', ...)handler (lines 209-210, 318-320).jQuery.data()decodes the attribute back to raw text forconfirm()— a text-only sink. -
This run (
fix/issue-1561): closed the last two unescaped interpolations on the same screen — the type and node<option>builders inloadMeta():- line 159:
t.name→escAttr(t.name); - line 169:
n.name→escAttr(n.name)in value + text (mirrors siblingcfieldsAssignView.html:200,207).
- line 159:
- Hostile name/label render inert — cell HTML
"> <img src=x onerror=alert(73)>/evil <b>bold</b>,td.querySelector('img') === null, no alert fired.

- Delete confirm shows the raw name as plain text (non-injectable); DELETE 200 removes the row.

- Type/Node selects populate identically; edit modal title via
.text(); create-via-modal works. - Event Viewer clean (only log_level 16 NOTICE audit rows; zero Error/Warning).
-
gui/templates/cfields/cfieldsView.html— 2 one-line escapes (fix run; cell/actions hardening already inb7aaee02e). -
tmp/TLU_Test_Cases.md— Regression — Issue #1561 suite (5/5 PASS). -
CHANGELOG— KEY BUGFIX (security) entry.
5/5 PASS, Event Viewer clean, issue closed. (Refs #1561)