Skip to content

[bot] Fast-forward for 25.7.21 - #1190

Merged
github-actions[bot] merged 3 commits into
release25.7from
25.7_ff_bot_25.7.21
Aug 25, 2026
Merged

[bot] Fast-forward for 25.7.21#1190
github-actions[bot] merged 3 commits into
release25.7from
25.7_ff_bot_25.7.21

Conversation

@github-actions

Copy link
Copy Markdown

Generated automatically.
Approve all matching PRs simultaneously.
Approval will trigger automatic merge.
View all PRs: https://internal.labkey.com/Scrumtime/Backlog/harvest-gitOpenPullRequests.view?branch=25.7_ff_bot_25.7.21

#### Rationale

EHR_BillingManager.deleteBillingRuns() filtered the invoice,
invoicedItems, and miscCharges tables by objectid/invoiceId alone, with
no container clause. Since DeleteBillingPeriodAction only checks
EHR_BillingAdminPermission in the current container, a billing admin in
one container could delete invoices and invoiced items, or detach misc
charges, in any other container by submitting foreign objectids. All
filters are now container-scoped via
SimpleFilter.createContainerFilter().

#### Related Pull Requests

* None

#### Changes

* EHR_BillingManager: all delete/preview filters in deleteBillingRuns()
are now container-scoped via a new createContainerScopedInFilter()
helper.
* EHR_BillingManager.TestCase: new integration test that seeds a
complete billing run in each of two folders and verifies cross-container
ids are ignored by both the testOnly preview and the actual delete,
while same-container deletion still removes the run and detaches its
misc charges.
* EHR_BillingModule: registers the test via getIntegrationTests().
…ner authz (#1152)

#### Rationale
Two related EHR security items surfaced during a security review. (1)
EHRDemographicsService serves animal records built under the elevated
EHR service user (EHRService.getEHRUser), so callers receive aggregated
demographic/derived fields regardless of their per-dataset / QCState row
permissions — and many DemographicsProviders set _supportsQCState=false,
applying no QCState filter at all. This is intended behavior (within an
EHR study folder, Read access is the trust boundary for the demographics
summary, which backs the shared EHR.DemographicsCache UIs), so it is now
documented in code to prevent a future caller from re-exposing these
records at a lower trust boundary. (2)
SetGeneticCalculationTaskSettingsAction enforced AdminPermission only on
the request container while resolving and acting on a caller-supplied
containerPath for the server-global genetic-calculation schedule, so a
user who administers the request container could point the schedule at a
container they do not administer. That gap is closed and covered by an
integration test.

#### Related Pull Requests
* None

#### Changes
* Document elevated-access-by-design on
EHRDemographicsServiceImpl.getAnimals and
EHRController.GetDemographicsAction, warning callers not to forward
these records to a lower trust boundary without re-securing them against
the consuming user.
* Re-verify AdminPermission on the resolved target container in
SetGeneticCalculationTaskSettingsAction and throw UnauthorizedException
when the caller does not administer it.
* Add EHRController.TestCase, an integration test verifying that a user
who administers the request container but not the resolved target is
rejected while a user who administers the target succeeds; registered in
EHRModule.getIntegrationTests().
## Rationale

BillingNotification.createChargeSummaryReport built its
per-financial-analyst tables by concatenating editor-entered database
values (investigator, project, debitedAccount, projectNumber, 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. The adjacent
Charge Summary category table already escaped its values with
PageFlowUtil.filter; this loop was simply never given the same
treatment.

## Related Pull Requests

None.

## Changes

- Wrap every editor-entered value (investigator, project, account,
project number, category) in PageFlowUtil.filter before rendering it
into the charge summary tables.
- Filter the derived href URLs (project, account, and
per-field-descriptor links), which embed those same tainted values.
@github-actions
github-actions Bot merged commit 21d8347 into release25.7 Aug 25, 2026
18 of 20 checks passed
@github-actions
github-actions Bot deleted the 25.7_ff_bot_25.7.21 branch August 25, 2026 18:37
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.

3 participants