Skip to content

Fix stored XSS in finance notification charge summary report#1779

Open
labkey-martyp wants to merge 3 commits into
release26.3-SNAPSHOTfrom
26.3_fb_finance_notification_xss
Open

Fix stored XSS in finance notification charge summary report#1779
labkey-martyp wants to merge 3 commits into
release26.3-SNAPSHOTfrom
26.3_fb_finance_notification_xss

Conversation

@labkey-martyp

@labkey-martyp labkey-martyp commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Rationale

FinanceNotification.writeResultTable builds the ONPRC charge summary report by concatenating editor-entered database values (financial analyst, project, alias/account, OGA project number, category) and their derived URLs directly into HTML with no escaping. That HTML is rendered verbatim into the LDK RunNotificationAction admin preview via HtmlString.unsafe and is also sent as the HTML email body, so a stored payload in any of those project/alias fields executed in the browser of any user who previewed the notification or received the email — a stored XSS with privilege-escalation potential toward admins. This is the ONPRC counterpart to the BillingNotification fix. DCMFinanceNotification was a registered subclass that overrode writeResultTable with a near-duplicate copy of the same unescaped report; rather than carry and fix a second copy, it is removed entirely.

Related Pull Requests

Changes

  • FinanceNotification: wrap every editor-entered value (financial analyst, project, account, project number, category) and its derived href URL in PageFlowUtil.filter in the per-financial-analyst tables, and filter the top category summary table (url and category), which was unescaped in this copy; add the org.labkey.api.util.PageFlowUtil import.
  • DCMFinanceNotification: remove the class entirely and drop its NotificationService registration and import from ONPRC_BillingModule.

FinanceNotification.createChargeSummaryReport is a divergent copy of the ehr_billing BillingNotification report and interpolated editor-entered database values (investigator, project, debitedAccount, projectNumber, category) and their derived URLs directly into HTML without escaping. That HTML is rendered verbatim into the LDK RunNotificationAction admin preview via HtmlString.unsafe and is also sent as the HTML email body, so a stored payload in any of those project/alias fields executed in the browser of any user who previewed the notification or received the email. Wrap every tainted value with PageFlowUtil.filter in both the per-financial-analyst tables and the top category summary table (which was also unescaped in this copy), matching the fix applied to BillingNotification.
DCMFinanceNotification overrides FinanceNotification.writeResultTable with its own copy of the report, so the escaping fix to the parent class did not cover it. It concatenated editor-entered database values (project, alias/account, OGA project number, category) and their derived URLs directly into HTML without escaping, reaching the same LDK RunNotificationAction admin preview (HtmlString.unsafe) and HTML email sink. It is registered as an active notification in ONPRC_BillingModule. Wrap every tainted value with PageFlowUtil.filter in both the per-project tables and the top category summary table, mapping to this override's token layout (tokens[0] project, tokens[1] alias, tokens[2] OGA project number).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant