Skip to content

Address reported security issues in the LINCS module#652

Merged
vagisha merged 3 commits into
release26.3-SNAPSHOTfrom
26.3_fb_lincs-security
Jun 29, 2026
Merged

Address reported security issues in the LINCS module#652
vagisha merged 3 commits into
release26.3-SNAPSHOTfrom
26.3_fb_lincs-security

Conversation

@vagisha

@vagisha vagisha commented Jun 29, 2026

Copy link
Copy Markdown
Collaborator

Rationale

A security review of the LINCS module identified six issues, addressed here:

  • High - path traversal (arbitrary file read + delete) in DownloadCustomGCTReportAction
  • Medium / Low - PSP job lookups not container-scoped (cross-folder data access)
  • Low (CWE-319) - Clue/PSP API key transmittable over http
  • Low - credential / config changes not audited

Changes

Path traversal (High) - DownloadCustomGCTReportAction

  • Validate the requested fileName with FileUtil.isAllowedFileName and confirm the resolved path stays inside the container's GCT directory.

Cross-container access (Medium / Low) - PSP job lookups

  • LincsManager.getLincsPspJob / getLincsPspJobForRun now require a Container and filter on it.
    The PSP-job detail/status/update actions can no longer reach jobs in other folders.
    All callers updated (3 controller actions, SubmitPspJobAction, and 2 LincsDataTable display columns).

Cleartext credential transmission (Low, CWE-319) - Clue/PSP server URI

  • Require https for the Clue/PSP server URI: rejected at save time in ManageLincsClueCredentials.validateCommand,
    and as defense in depth in LincsPspUtil.getPspEndpoint before the API key is sent as a request header.
    The point-of-use check also blocks endpoints saved as http:// before this fix.
  • Added <labkey:errors/> to manageClueCredentials.jsp so the save-time rejection is actually shown.

Missing audit trail (Low) - credential / config changes

  • ManageLincsClueCredentials.handlePost and CromwellConfigAction.handlePost now write an audit event (container and acting user, no secret values) when the PSP/Clue credentials or Cromwell config change.

Co-Authored-By: Claude noreply@anthropic.com

vagisha and others added 2 commits June 28, 2026 15:49
* DownloadCustomGCTReportAction.getView: validates the requested fileName and confines the resolved path to the container's GCT directory before streaming and deleting it, closing a path-traversal arbitrary file read/delete reachable by any Reader.
* LincsManager.getLincsPspJob/getLincsPspJobForRun: requires a Container and filters on it, so PSP-job detail/status/update actions can no longer reach jobs in other folders by guessing an id (cross-container IDOR). Updated all callers.
* Requires https for the Clue/PSP server URI, rejects both at save (ManageLincsClueCredentials) and at use (LincsPspUtil.getPspEndpoint), so the API key is never sent in clear text (CWE-319, cleartext transmission of sensitive data).
* ManageLincsClueCredentials and CromwellConfigAction: write an audit event (no secret values) when credentials or config change.

Identified by a security review of the MacCoss lab modules.

Co-Authored-By: Claude <noreply@anthropic.com>
…ired

  rejection from ManageLincsClueCredentials.validateCommand is shown.
* Clarified the comments on the PSP endpoint https check (LincsPspUtil) and the
  Cromwell config audit event (LincsController). No behavior change.
@vagisha vagisha marked this pull request as ready for review June 29, 2026 00:28

@ankurjuneja ankurjuneja left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @vagisha , here is one finding from claude code review using LK skills that I think is relevant here:

Finding #1 - [Severity: Medium] — Consistency / IDOR gap — LincsManager.deleteLincsPspJobsForRun(long runId)

▎ Issue: The PR added a Container parameter to getLincsPspJobForRun and getLincsPspJob, but deleteLincsPspJobsForRun(long runId) (visible just below in the same file) was left filtering by RunId only, with no container filter.
▎ Why it matters: If this method is ever reachable with an attacker-influenced runId, it would delete PSP jobs across container boundaries — the same class of issue the rest of the PR closes. It's likely only invoked internally on run-deletion events (where the run is already container-scoped), which would make it safe, but that should be confirmed.
▎ Suggestion: Verify the call sites. If any path takes a request-supplied runId, add SimpleFilter.createContainerFilter(container) here too for symmetry.

@vagisha

vagisha commented Jun 29, 2026

Copy link
Copy Markdown
Collaborator Author

Thanks, @ankurjuneja. deleteLincsPspJobsForRun has exactly one caller, and the runId it passes is container-scoped. The runId is never supplied by a user request. So the current code is safe in practice, but I added container-filtering to be consistent - 289226a

@vagisha vagisha merged commit a84efa0 into release26.3-SNAPSHOT Jun 29, 2026
5 checks passed
@vagisha vagisha deleted the 26.3_fb_lincs-security branch June 29, 2026 17:38
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.

2 participants