Skip to content

[WIP] Fix 64 trust boundary violations in HTTP session handling#1081

Closed
yingbull with Copilot wants to merge 3 commits into
developfrom
copilot/fix-trust-boundary-violations
Closed

[WIP] Fix 64 trust boundary violations in HTTP session handling#1081
yingbull with Copilot wants to merge 3 commits into
developfrom
copilot/fix-trust-boundary-violations

Conversation

Copilot AI commented Apr 5, 2026

Copy link
Copy Markdown
Contributor
  • Fix dxSetupResearch2Action.java — validate demographicNo/providerNo as integers
  • Fix dxResearchCodeSearch2Action.java — validate codeType + xml_research with Encode.forHtml
  • Fix MsgViewMessage2Action.java — store validated int string for messageNo/messagePosition; allowlist from; encode orderBy
  • Fix DxresearchReport2Action.java — encode editingCodeDesc, codeSingle, codeSystem
  • Fix ProgramManagerView2Action.java — validate programId as int; encode notes
  • Fix ClientSearchAction22Action.java — validate noteId as int
  • Fix WLSetupDisplayPatientWaitingList2Action.java — validate demographicNo as int
  • Fix WLSetupDisplayWaitingList2Action.java — validate waitingListId as int
  • Fix DocumentUpload2Action.java — store validated int for preferredQueue (both paths)
  • Fix AddEditDocument2Action.java — store validated int for preferredQueue
  • Fix EctSetupMeasurements2Action.java — encode groupName before bean construction
  • Fix SystemMessage2Action.java — store String.valueOf(parsedInt) instead of raw
  • Fix SQLReporter.java — validate templateId as int to break taint chain
  • Fix Login2Action.java — apply Encode.forHtml to userName/pin in setUserInfoToSession
  • Fix AddEForm2Action.java + EmailAttachmentSettings.java — validateIdArray helper for attachment arrays; validate demographic_no as int; encode eform_link; encode all string email fields in factory method
  • Fix annotation.jsp — validate attrib_name as safe session key (alphanumeric/underscore/hyphen/dot)
  • Fix uploadimage.jsp — validate demographicNo as int
  • Fix providerupdatepreference.jsp — validate case_program_id as int; encode site value

Summary by CodeRabbit

Release Notes

  • Bug Fixes
    • Enhanced validation for numeric identifiers across forms and parameter handling to ensure data integrity
    • Added text encoding for user-provided inputs to prevent display inconsistencies
    • Implemented parameter sanitization with stricter validation patterns for session attributes

Validate all HTTP request parameters before storing them in the HTTP
session, breaking the CodeQL taint chain for java/TrustBoundaryViolation
alerts.

Patterns applied:
- Numeric IDs (demographicNo, providerNo, programId, queueId, noteId,
  waitingListId, templateId, messageNo/Position, fdid, attachment arrays):
  parse with ConversionUtils.fromIntString() or Integer.parseInt() and
  store String.valueOf(int), producing an untainted string.
- String identifiers used as session keys (attrib_name, eform_link):
  validate against an allowlist regex or apply Encode.forHtml() so a
  malicious key cannot be injected into the session namespace.
- Free-text strings stored in session (codeType, xml_research, groupName,
  orderBy, dischargeNotes, admissionNotes, userName, pin, email fields):
  apply Encode.forHtml() which is a recognised CodeQL sanitiser.
- 'from' parameter in MsgViewMessage2Action: validated against an explicit
  allowlist of known values before session storage.

Files changed: dxSetupResearch2Action, dxResearchCodeSearch2Action,
MsgViewMessage2Action, DxresearchReport2Action, ProgramManagerView2Action,
ClientSearchAction22Action, WLSetupDisplayPatientWaitingList2Action,
WLSetupDisplayWaitingList2Action, DocumentUpload2Action,
AddEditDocument2Action, EctSetupMeasurements2Action, SystemMessage2Action,
SQLReporter, Login2Action, AddEForm2Action + EmailAttachmentSettings,
annotation.jsp, uploadimage.jsp, providerupdatepreference.jsp

Agent-Logs-Url: https://github.com/carlos-emr/carlos/sessions/6b4542f0-580c-42f2-b087-2d09e83485ca

Co-authored-by: yingbull <8680161+yingbull@users.noreply.github.com>
@yingbull yingbull marked this pull request as ready for review April 5, 2026 14:06
Copilot AI review requested due to automatic review settings April 5, 2026 14:06
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@yingbull

yingbull commented Apr 5, 2026

Copy link
Copy Markdown
Collaborator

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Apr 5, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@sourcery-ai sourcery-ai Bot 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.

Sorry @yingbull, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@penify-dev

penify-dev Bot commented Apr 5, 2026

Copy link
Copy Markdown
Contributor

Failed to generate code suggestions for PR

@coderabbitai

coderabbitai Bot commented Apr 5, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Bot user detected.

To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 1a12fe25-e584-45a5-b5fe-b5b04e1cda2f

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This pull request applies input validation and sanitization across multiple Java action classes and JSP files. Changes include converting string request parameters to integers using ConversionUtils.fromIntString(), HTML-encoding user-provided strings with Encode.forHtml() before session storage, validating against allowlists, and normalizing parameters before downstream use.

Changes

Cohort / File(s) Summary
Numeric ID & Parameter Validation
src/main/java/io/github/carlos_emr/carlos/PMmodule/web/ClientSearchAction22Action.java, src/main/java/io/github/carlos_emr/carlos/www/SystemMessage2Action.java, src/main/java/io/github/carlos_emr/carlos/waitinglist/pageUtil/WLSetupDisplay...Action.java (2 files), src/main/java/io/github/carlos_emr/carlos/report/reportByTemplate/SQLReporter.java
Parse request parameter IDs (noteId, id, demographic_no, waitingListId, templateId) via ConversionUtils.fromIntString() and conditionally store validated/normalized integer-derived strings in session attributes, replacing direct raw parameter assignment.
HTML Encoding of Free-Text Session Values
src/main/java/io/github/carlos_emr/carlos/PMmodule/web/admin/ProgramManagerView2Action.java, src/main/java/io/github/carlos_emr/carlos/commn/web/DxresearchReport2Action.java, src/main/java/io/github/carlos_emr/carlos/dxresearch/pageUtil/dxResearchCodeSearch2Action.java, src/main/java/io/github/carlos_emr/carlos/eform/actions/AddEForm2Action.java, src/main/java/io/github/carlos_emr/carlos/email/core/EmailAttachmentSettings.java, src/main/java/io/github/carlos_emr/carlos/encounter/oscarMeasurements/pageUtil/EctSetupMeasurements2Action.java, src/main/java/io/github/carlos_emr/carlos/login/Login2Action.java, src/main/java/io/github/carlos_emr/carlos/messenger/pageUtil/MsgViewMessage2Action.java
Apply Encode.forHtml() to user-provided strings (dischargeNotes, admissionNotes, codesc, codeSystem, eform_link, groupName, userName, pin, orderBy) before storing in session or using downstream.
Provider & Site Parameter Normalization
src/main/java/io/github/carlos_emr/carlos/dxresearch/pageUtil/dxSetupResearch2Action.java, src/main/webapp/provider/providerupdatepreference.jsp
Validate numeric provider/program IDs via ConversionUtils.fromIntString() and HTML-encode site parameter; apply allowlist constraints and defaults for providerNo and site_selected session attributes.
Document Queue Parameter Handling
src/main/java/io/github/carlos_emr/carlos/documentManager/actions/AddEditDocument2Action.java, src/main/java/io/github/carlos_emr/carlos/documentManager/actions/DocumentUpload2Action.java
Parse queueId via ConversionUtils.fromIntString() and store String.valueOf() of the validated integer in preferredQueue session attribute instead of raw request string.
Message & Navigation Parameter Validation
src/main/java/io/github/carlos_emr/carlos/messenger/pageUtil/MsgViewMessage2Action.java
Convert messageID and messagePosition to validated integers, apply allowlist for from parameter (inbox, sent, trash, messenger), and HTML-encode orderBy before session storage.
JSP Input Validation
src/main/webapp/annotation/annotation.jsp, src/main/webapp/casemgmt/uploadimage.jsp
Add pattern validation for attrib_name (regex [a-zA-Z0-9_\-.]*) and numeric parsing with exception handling for clientId parameter before session attribute operations.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related issues

Possibly related PRs

Suggested labels

Bug fix, Review effort [1-5]: 4, Security, Input Validation

Poem

🐰 Hops of validation, bounds so tight,
Encoding strings to set things right,
No more raw params in the session stash,
Sanitized integers, no XSS rash!
Secure the warren, hop with care! 🔐

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 22.73% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change—fixing trust boundary violations in HTTP session handling across multiple files, which is the primary focus of all modifications in the changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch copilot/fix-trust-boundary-violations
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch copilot/fix-trust-boundary-violations

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copilot AI 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.

Pull request overview

This WIP PR aims to address CodeQL java/TrustBoundaryViolation findings by breaking HTTP-parameter taint chains before values are persisted into the HTTP session (and related flows) across several Struts actions and JSPs.

Changes:

  • Added integer parsing/canonicalization before storing various IDs (demographic, program, waiting list, message, queue, template) into session/request state.
  • Added output-encoding in several places prior to session storage to satisfy CodeQL trust-boundary expectations.
  • Introduced helpers for request-array ID validation (eForm attachment IDs) and tightened session attribute key handling (annotation.jsp).

Reviewed changes

Copilot reviewed 19 out of 19 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
src/main/webapp/provider/providerupdatepreference.jsp Validates case_program_id; stores site_selected with encoding.
src/main/webapp/casemgmt/uploadimage.jsp Parses demographicNo before storing clientId in session.
src/main/webapp/annotation/annotation.jsp Restricts attrib_name to a safe session attribute-name pattern.
src/main/java/io/github/carlos_emr/carlos/www/SystemMessage2Action.java Stores canonicalized systemMessageId in session.
src/main/java/io/github/carlos_emr/carlos/waitinglist/pageUtil/WLSetupDisplayWaitingList2Action.java Parses waitingListId via ConversionUtils before use/storage.
src/main/java/io/github/carlos_emr/carlos/waitinglist/pageUtil/WLSetupDisplayPatientWaitingList2Action.java Parses demographic_no via ConversionUtils and stores in session.
src/main/java/io/github/carlos_emr/carlos/report/reportByTemplate/SQLReporter.java Parses templateId via ConversionUtils before fetching templates.
src/main/java/io/github/carlos_emr/carlos/PMmodule/web/ClientSearchAction22Action.java Parses noteId and only stores it when positive.
src/main/java/io/github/carlos_emr/carlos/PMmodule/web/admin/ProgramManagerView2Action.java Parses id/clientId; stores admission notes in session with encoding.
src/main/java/io/github/carlos_emr/carlos/messenger/pageUtil/MsgViewMessage2Action.java Stores validated message IDs/position; allowlists from; encodes orderBy.
src/main/java/io/github/carlos_emr/carlos/login/Login2Action.java Encodes userName and pin before session storage.
src/main/java/io/github/carlos_emr/carlos/encounter/oscarMeasurements/pageUtil/EctSetupMeasurements2Action.java Encodes groupName before bean construction and request/session usage.
src/main/java/io/github/carlos_emr/carlos/email/core/EmailAttachmentSettings.java Encodes multiple email-related request parameters in factory method.
src/main/java/io/github/carlos_emr/carlos/eform/actions/AddEForm2Action.java Adds validateIdArray; parses demographic_no; encodes eform_link; stores email settings into session.
src/main/java/io/github/carlos_emr/carlos/dxresearch/pageUtil/dxSetupResearch2Action.java Parses demographicNo; parses/normalizes providerNo before session storage.
src/main/java/io/github/carlos_emr/carlos/dxresearch/pageUtil/dxResearchCodeSearch2Action.java Encodes code-search terms and codeType before session storage.
src/main/java/io/github/carlos_emr/carlos/documentManager/actions/DocumentUpload2Action.java Stores canonicalized preferredQueue (validated int string).
src/main/java/io/github/carlos_emr/carlos/documentManager/actions/AddEditDocument2Action.java Stores canonicalized preferredQueue (validated int string).
src/main/java/io/github/carlos_emr/carlos/commn/web/DxresearchReport2Action.java Encodes several dx-research values prior to DB/session usage.
Comments suppressed due to low confidence (2)

src/main/java/io/github/carlos_emr/carlos/eform/actions/AddEForm2Action.java:122

  • eform_link is used as a session attribute key (se.setAttribute(eform_link, fdid)). Encoding it with Encode.forHtml does not validate it as a safe key and can also change the key, breaking the postback mechanism. Prefer validating eform_link against a safe key pattern/allowlist (similar to annotation.jsp) and store/use the validated raw key; don’t apply HTML output encoding to keys.
        // Validate demographicNo as integer to break taint chain before session/request storage
        String demographic_no = String.valueOf(ConversionUtils.fromIntString(request.getParameter("efmdemographic_no")));
        // Encode eform_link to prevent tainted session attribute key
        String eform_link = Encode.forHtml(request.getParameter("eform_link"));
        String subject = request.getParameter("subject");

        /*
         * Part 2 of "counter hack for a hack" initialized in Javascript file
         * eform_floating_toolbar.js

src/main/java/io/github/carlos_emr/carlos/commn/web/DxresearchReport2Action.java:296

  • Encoding codesearch/codesystem before calling codingSystemManager.getCodeDescription() and storing into session changes the actual code values and can break lookups (and may persist encoded values later). These values should be validated/allowlisted (e.g., known coding systems) but not HTML-encoded prior to business logic; encode at output instead.
        String quickListName = this.getQuickListName();
        List<dxCodeSearchBean> codeSearch = dxresearchdao.getQuickListItems(quickListName);
        // Encode user-supplied code values to break taint chain before session storage
        String codeSingle = Encode.forHtml(request.getParameter("codesearch"));
        String codeSystem = Encode.forHtml(request.getParameter("codesystem"));
        String action = request.getParameter("action");
        dxCodeSearchBean newAddition = null;

        // check the code
        CodingSystemManager codingSystemManager = SpringUtils.getBean(CodingSystemManager.class);
        String codeDescription = null;

        if (codeSystem != null && !codeSystem.isEmpty()) {
            codeDescription = codingSystemManager.getCodeDescription(codeSystem.toLowerCase().trim(), codeSingle);
        }

        if (codeDescription != null && !codeDescription.isEmpty()) {
            newAddition = new dxCodeSearchBean();
            newAddition.setType(codeSystem);
            newAddition.setDxSearchCode(codeSingle);
            newAddition.setDescription(codeDescription);

Comment on lines 111 to 115
String selected_site = (String) request.getParameter("site");
if (selected_site != null) {
session.setAttribute("site_selected", (selected_site.equals("none") ? null : selected_site));
// Encode site value to break taint chain before session storage
session.setAttribute("site_selected", ("none".equals(selected_site) ? null : org.owasp.encoder.Encode.forHtml(selected_site)));
}

Copilot AI Apr 5, 2026

Copy link

Choose a reason for hiding this comment

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

Encoding the site identifier with Encode.forHtml before storing it in session will change the value (e.g., "&" -> "&") and can break downstream lookups that expect the raw site key (e.g., SiteDao.getProviderNoBySiteLocation(selectedSite) in appointmentprovideradminday.jsp). Prefer validating/allowlisting the site against active sites and storing the canonical raw key (or null for "none"), and only HTML-encode when rendering.

Copilot uses AI. Check for mistakes.
Comment on lines 101 to 110
// Validate demographicNo as an integer to break taint chain before session storage
String demographicNoParam = request.getParameter("demographicNo");
String validatedDemoNo;
try {
validatedDemoNo = String.valueOf(Integer.parseInt(demographicNoParam == null ? "" : demographicNoParam.trim()));
} catch (NumberFormatException e) {
validatedDemoNo = "0";
}
request.getSession().setAttribute("clientId", validatedDemoNo);
%>

Copilot AI Apr 5, 2026

Copy link

Choose a reason for hiding this comment

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

Falling back to "0" on invalid demographicNo means ClientImage2Action will happily parseInt("0") and attempt to save/delete an image for demographic 0. Instead, treat invalid/missing demographicNo as an error (don’t set the session attribute, and show an error/redirect) and only proceed when the parsed ID is > 0.

Copilot uses AI. Check for mistakes.
Comment on lines +62 to 66
// Validate demographicNo as a positive integer to break taint chain before session storage
Integer parsedDemoNo = ConversionUtils.fromIntString(request.getParameter("demographic_no"));
String demographicNo = String.valueOf(parsedDemoNo);
DemographicData demoData = new DemographicData();
Demographic demo = demoData.getDemographic(LoggedInInfo.getLoggedInInfoFromSession(request), demographicNo);

Copilot AI Apr 5, 2026

Copy link

Choose a reason for hiding this comment

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

ConversionUtils.fromIntString returns 0 for null/invalid input. Converting that to "0" and then calling getDemographic(..., demographicNo) will likely return null, leading to a NullPointerException when building demoInfo. Add a guard for parsedDemoNo > 0 and handle invalid IDs (redirect / error) before dereferencing the Demographic.

Suggested change
// Validate demographicNo as a positive integer to break taint chain before session storage
Integer parsedDemoNo = ConversionUtils.fromIntString(request.getParameter("demographic_no"));
String demographicNo = String.valueOf(parsedDemoNo);
DemographicData demoData = new DemographicData();
Demographic demo = demoData.getDemographic(LoggedInInfo.getLoggedInInfoFromSession(request), demographicNo);
// Validate demographicNo as a positive integer before lookup and session storage
Integer parsedDemoNo = ConversionUtils.fromIntString(request.getParameter("demographic_no"));
if (parsedDemoNo == null || parsedDemoNo <= 0) {
addActionError("Invalid patient identifier.");
return ERROR;
}
String demographicNo = String.valueOf(parsedDemoNo);
DemographicData demoData = new DemographicData();
Demographic demo = demoData.getDemographic(LoggedInInfo.getLoggedInInfoFromSession(request), demographicNo);
if (demo == null) {
addActionError("Patient not found.");
return ERROR;
}

Copilot uses AI. Check for mistakes.
Comment on lines 70 to 73
// Encode groupName to break taint chain before using it in bean construction and session storage
String groupName = Encode.forHtml(request.getParameter("groupName"));
EctValidation ectValidation = new EctValidation();
String css = ectValidation.getCssPath(groupName);

Copilot AI Apr 5, 2026

Copy link

Choose a reason for hiding this comment

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

Encode.forHtml is output encoding, not input validation. Encoding groupName before querying MeasurementGroupStyleDao.findByGroupName and constructing EctMeasurementTypesBeanHandler can change the group name and cause missing styles/types. Prefer validating groupName against an allowlist (or a safe pattern/known groups) and store/use the canonical raw value; apply HTML encoding only when rendering groupName in the response.

Copilot uses AI. Check for mistakes.
Comment on lines 60 to 69
String[] xml_research = new String[5];
xml_research[0] = request.getParameter("xml_research1");
xml_research[1] = request.getParameter("xml_research2");
xml_research[2] = request.getParameter("xml_research3");
xml_research[3] = request.getParameter("xml_research4");
xml_research[4] = request.getParameter("xml_research5");
String codeType = request.getParameter("codeType");
// Encode each search-term value to break the taint chain before session storage
xml_research[0] = Encode.forHtml(request.getParameter("xml_research1"));
xml_research[1] = Encode.forHtml(request.getParameter("xml_research2"));
xml_research[2] = Encode.forHtml(request.getParameter("xml_research3"));
xml_research[3] = Encode.forHtml(request.getParameter("xml_research4"));
xml_research[4] = Encode.forHtml(request.getParameter("xml_research5"));
String codeType = Encode.forHtml(request.getParameter("codeType"));

dxCodeSearchBeanHandler hd = new dxCodeSearchBeanHandler(codeType, xml_research);

Copilot AI Apr 5, 2026

Copy link

Choose a reason for hiding this comment

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

HTML-encoding search keywords and codeType before passing them into dxCodeSearchBeanHandler will change user search input and can break matching in DxDao.findCodingSystemDescription (e.g., "&" becomes "&"). The JSP already output-encodes codeType and results. Prefer leaving search terms raw for querying (with length/pattern validation as needed) and only encode at render time.

Copilot uses AI. Check for mistakes.
Comment on lines 97 to 112
hrmDocs,
forms,
!"false".equals(req.getParameter("attachEFormToEmail")),
"true".equals(req.getParameter("openEFormAfterSendingEmail")),
!"false".equals(req.getParameter("enableEmailEncryption")),
!"false".equals(req.getParameter("encryptEmailAttachments")),
"true".equals(req.getParameter("autoSendEmail")),
"true".equals(req.getParameter("deleteEFormAfterSendingEmail")),
req.getParameter("passwordEmail"),
req.getParameter("passwordClueEmail"),
req.getParameter("senderEmail"),
req.getParameter("subjectEmail"),
req.getParameter("bodyEmail"),
req.getParameter("encryptedMessageEmail"),
req.getParameter("emailPatientChartOption")
Encode.forHtml(req.getParameter("passwordEmail")),
Encode.forHtml(req.getParameter("passwordClueEmail")),
Encode.forHtml(req.getParameter("senderEmail")),
Encode.forHtml(req.getParameter("subjectEmail")),
Encode.forHtml(req.getParameter("bodyEmail")),
Encode.forHtml(req.getParameter("encryptedMessageEmail")),
Encode.forHtml(req.getParameter("emailPatientChartOption"))
);

Copilot AI Apr 5, 2026

Copy link

Choose a reason for hiding this comment

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

EmailAttachmentSettings.of() HTML-encodes passwordEmail/passwordClueEmail/bodyEmail/etc. These values are later stored into session and used for email composition and (likely) PDF/email encryption; output encoding here will change the actual password/body content (e.g., '&' -> '&') and can break encryption or send corrupted content. Prefer keeping raw values for processing, validating as needed (length/charset), and only encoding when rendering into HTML.

Copilot uses AI. Check for mistakes.
Comment on lines +534 to +547
* Elements that are not valid integers are replaced with "0".
*
* @param rawIds the raw string array from the request, may be null
* @return a new array of validated integer strings, never null
*/
private static String[] validateIdArray(String[] rawIds) {
if (rawIds == null) {
return new String[0];
}
String[] validated = new String[rawIds.length];
for (int i = 0; i < rawIds.length; i++) {
validated[i] = String.valueOf(ConversionUtils.fromIntString(rawIds[i]));
}
return validated;

Copilot AI Apr 5, 2026

Copy link

Choose a reason for hiding this comment

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

validateIdArray replaces invalid IDs with "0". DocumentAttach.attachToEForm() will then persist EFormDocs rows with documentNo=0, creating invalid attachment records. Instead, filter out non-positive IDs (and potentially de-duplicate) so only valid IDs are attached.

Suggested change
* Elements that are not valid integers are replaced with "0".
*
* @param rawIds the raw string array from the request, may be null
* @return a new array of validated integer strings, never null
*/
private static String[] validateIdArray(String[] rawIds) {
if (rawIds == null) {
return new String[0];
}
String[] validated = new String[rawIds.length];
for (int i = 0; i < rawIds.length; i++) {
validated[i] = String.valueOf(ConversionUtils.fromIntString(rawIds[i]));
}
return validated;
* Only positive integer identifiers are retained; invalid, zero, and negative
* values are discarded. Duplicate identifiers are removed while preserving the
* original request order.
*
* @param rawIds the raw string array from the request, may be null
* @return a new array containing only unique positive integer strings, never null
*/
private static String[] validateIdArray(String[] rawIds) {
if (rawIds == null) {
return new String[0];
}
Set<String> validated = new LinkedHashSet<>();
for (String rawId : rawIds) {
int parsedId = ConversionUtils.fromIntString(rawId);
if (parsedId > 0) {
validated.add(String.valueOf(parsedId));
}
}
return validated.toArray(new String[0]);

Copilot uses AI. Check for mistakes.
Comment on lines 259 to 266
public String editDesc() {
String editingCodeType = request.getParameter("editingCodeType");
String editingCodeCode = request.getParameter("editingCodeCode");
String editingCodeDesc = request.getParameter("editingCodeDesc");
// Encode editingCodeDesc to break taint chain before session storage
String editingCodeDesc = Encode.forHtml(request.getParameter("editingCodeDesc"));

dxQuickListItemsHandler.updatePatientCodeDesc(editingCodeType, editingCodeCode, editingCodeDesc);

Copilot AI Apr 5, 2026

Copy link

Choose a reason for hiding this comment

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

Encode.forHtml is being applied to editingCodeDesc before calling updatePatientCodeDesc(...), which writes the description back to the coding system table. This will store HTML entities in the database and permanently corrupt the description. Store the raw description (with appropriate validation/length limits) and encode only when rendering to HTML.

Copilot uses AI. Check for mistakes.
Comment on lines +113 to +117
String fid = request.getParameter("efmfid");
String demographic_no = request.getParameter("efmdemographic_no");
String eform_link = request.getParameter("eform_link");
// Validate demographicNo as integer to break taint chain before session/request storage
String demographic_no = String.valueOf(ConversionUtils.fromIntString(request.getParameter("efmdemographic_no")));
// Encode eform_link to prevent tainted session attribute key
String eform_link = Encode.forHtml(request.getParameter("eform_link"));

Copilot AI Apr 5, 2026

Copy link

Choose a reason for hiding this comment

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

ConversionUtils.fromIntString returns 0 on missing/invalid input. Setting demographic_no to "0" allows the action to proceed and can result in saving/attaching an eForm against demographic 0 rather than failing fast. Prefer rejecting the request (or returning an error) when efmdemographic_no is missing/invalid instead of silently coercing to 0.

Copilot uses AI. Check for mistakes.
Comment on lines +67 to +73
// Validate providerNo: fall back to trusted logged-in provider; otherwise parse as integer
String providerNoParam = request.getParameter("providerNo");
String providerNo;
if (providerNoParam == null) {
providerNo = loggedInInfo.getLoggedInProviderNo();
} else {
providerNo = String.valueOf(ConversionUtils.fromIntString(providerNoParam));

Copilot AI Apr 5, 2026

Copy link

Choose a reason for hiding this comment

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

If providerNo is supplied but invalid, ConversionUtils.fromIntString will coerce it to 0 and the action will use/store providerNo="0" in session. It would be safer to ignore the request parameter unless it matches the logged-in provider (or at least fall back to loggedInInfo.getLoggedInProviderNo() when parsed value <= 0).

Suggested change
// Validate providerNo: fall back to trusted logged-in provider; otherwise parse as integer
String providerNoParam = request.getParameter("providerNo");
String providerNo;
if (providerNoParam == null) {
providerNo = loggedInInfo.getLoggedInProviderNo();
} else {
providerNo = String.valueOf(ConversionUtils.fromIntString(providerNoParam));
// Only trust providerNo when it matches the authenticated provider; otherwise fall back
String loggedInProviderNo = loggedInInfo.getLoggedInProviderNo();
String providerNo = loggedInProviderNo;
String providerNoParam = request.getParameter("providerNo");
if (providerNoParam != null) {
int requestedProviderNo = ConversionUtils.fromIntString(providerNoParam);
if (requestedProviderNo > 0 && String.valueOf(requestedProviderNo).equals(loggedInProviderNo)) {
providerNo = String.valueOf(requestedProviderNo);
}

Copilot uses AI. Check for mistakes.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 10

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/main/java/io/github/carlos_emr/carlos/email/core/EmailAttachmentSettings.java (1)

64-80: 🛠️ Refactor suggestion | 🟠 Major

Complete public method JavaDoc tags for repository policy compliance.

EmailAttachmentSettings.of(...) JavaDoc is missing method-level @since (and policy-required comprehensive tags set). Please align this block with the src/main/java JavaDoc rule.

As per coding guidelines: src/main/java/**/*.java: All public classes and methods MUST have comprehensive JavaDoc with @param, @return, @throws, and @since tags - do NOT use @author tags.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/io/github/carlos_emr/carlos/email/core/EmailAttachmentSettings.java`
around lines 64 - 80, Update the JavaDoc for the public factory method
EmailAttachmentSettings.of(...) to include the required repository policy tags:
add a `@since` tag with the current project version or date, ensure all `@param`
entries for req, fdid, demographicNo, eForms, docs, labs, hrmDocs, forms are
present and accurate, and include the `@return` tag (and `@throws` only if the
method can throw a checked exception); do not add `@author`. Keep the descriptive
text intact and align tagging style with other public methods in the codebase.
♻️ Duplicate comments (1)
src/main/java/io/github/carlos_emr/carlos/www/SystemMessage2Action.java (1)

73-74: ⚠️ Potential issue | 🟠 Major

Handle invalid id input without throwing from edit().

Line 73 parses an untrusted request parameter directly; malformed input still throws NumberFormatException and bypasses the intended “missing message” flow. Please catch parse failures and return list() with the existing action message path.

💡 Suggested patch
-            int parsedId = Integer.parseInt(messageId);
-            SystemMessage msg = systemMessageDao.find(parsedId);
+            int parsedId;
+            try {
+                parsedId = Integer.parseInt(messageId);
+            } catch (NumberFormatException e) {
+                addActionMessage(getText("system_message.missing"));
+                return list();
+            }
+            SystemMessage msg = systemMessageDao.find(parsedId);
#!/bin/bash
set -euo pipefail

# Verify the parse call exists and whether NumberFormatException is handled in this action.
fd -i 'SystemMessage2Action.java' | while read -r file; do
  echo "== $file =="
  rg -n -C4 'Integer\.parseInt\(messageId\)|catch\s*\(\s*NumberFormatException' "$file"
done
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/io/github/carlos_emr/carlos/www/SystemMessage2Action.java`
around lines 73 - 74, In SystemMessage2Action.edit(),
Integer.parseInt(messageId) can throw NumberFormatException for malformed input;
wrap the parse and subsequent systemMessageDao.find(parsedId) call in a
try/catch that catches NumberFormatException and handles it by returning list()
(the existing action path for "missing message") instead of letting the
exception propagate; ensure you reference the edit() method and the
systemMessageDao.find(...) call so the failure branch sets the same response
state as the "message not found" flow.
🧹 Nitpick comments (2)
src/main/java/io/github/carlos_emr/carlos/commn/web/DxresearchReport2Action.java (1)

278-280: Same encoding concern applies to codeSingle/codeSystem as in dxResearchCodeSearch2Action.

These values are used in codingSystemManager.getCodeDescription() lookup at line 289. If coding system identifiers contain special characters, HTML encoding could break lookups. See the verification comment on dxResearchCodeSearch2Action.java for details.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/io/github/carlos_emr/carlos/commn/web/DxresearchReport2Action.java`
around lines 278 - 280, The code is HTML-encoding request parameters into
codeSingle/codeSystem before calling codingSystemManager.getCodeDescription(),
which can break lookups; instead obtain the raw parameter values (use
request.getParameter("codesearch") / request.getParameter("codesystem") without
Encode.forHtml), validate/normalize them against allowed coding-system
identifiers or a whitelist, then pass the validated raw values into
codingSystemManager.getCodeDescription(); if you must store or render these
values later, apply Encode.forHtml at output time only (or encode when
persisting to session separately) to avoid breaking the lookup while preserving
XSS protection.
src/main/java/io/github/carlos_emr/carlos/documentManager/actions/DocumentUpload2Action.java (1)

130-132: Consider adding an import for ConversionUtils for consistency.

The validation correctly breaks the taint chain by parsing queueId before session storage. However, the fully qualified class name is verbose compared to other utility usages in this file. Consider adding an import statement.

Note: If queueId is null or not a valid integer, verify that fromIntString() handles this gracefully (e.g., returns a sensible default or throws). The file operations at lines 117-129 use queueId before this validation, so downstream session storage shouldn't fail silently if earlier operations succeeded.

♻️ Suggested import addition

Add to imports section (around line 45):

import io.github.carlos_emr.carlos.util.ConversionUtils;

Then simplify line 131:

-                int parsedQueueId = io.github.carlos_emr.carlos.util.ConversionUtils.fromIntString(queueId);
+                int parsedQueueId = ConversionUtils.fromIntString(queueId);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/io/github/carlos_emr/carlos/documentManager/actions/DocumentUpload2Action.java`
around lines 130 - 132, Add an import for
io.github.carlos_emr.carlos.util.ConversionUtils and replace the fully-qualified
call to io.github.carlos_emr.carlos.util.ConversionUtils.fromIntString(queueId)
with ConversionUtils.fromIntString(queueId) in DocumentUpload2Action; ensure the
variable parsedQueueId and the subsequent
request.getSession().setAttribute("preferredQueue",
String.valueOf(parsedQueueId)) remain unchanged and verify that
ConversionUtils.fromIntString handles null/invalid queueId cases (returns a
sensible default or throws) so session storage behavior is consistent with
earlier file operations.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@src/main/java/io/github/carlos_emr/carlos/dxresearch/pageUtil/dxSetupResearch2Action.java`:
- Around line 65-74: The current code coerces invalid IDs into "0" by calling
String.valueOf(ConversionUtils.fromIntString(...)) which creates a bogus
patient/provider context; change the logic to check the result of
ConversionUtils.fromIntString before converting to String: for demographicNo
call ConversionUtils.fromIntString(request.getParameter("demographicNo")) and if
it returns an invalid/NULL/negative value handle it by rejecting the request
(throwing/returning an error/redirect) instead of using "0"; for providerNo
first check request.getParameter("providerNo") – if null use
loggedInInfo.getLoggedInProviderNo(), otherwise parse with
ConversionUtils.fromIntString and if it’s invalid do not coerce to "0" but treat
it as a validation failure (reject) or explicitly fall back only when you decide
that is acceptable; reference variables/methods: demographicNo, providerNoParam,
providerNo, ConversionUtils.fromIntString, loggedInInfo.getLoggedInProviderNo.

In
`@src/main/java/io/github/carlos_emr/carlos/email/core/EmailAttachmentSettings.java`:
- Around line 105-111: Add a `@since` tag to the JavaDoc for the public method in
class EmailAttachmentSettings that processes the request parameters using
Encode.forHtml (the method invoking Encode.forHtml(req.getParameter(...)) for
passwordEmail, passwordClueEmail, senderEmail, subjectEmail, bodyEmail,
encryptedMessageEmail, emailPatientChartOption); update that method's JavaDoc to
include `@since` with the current project version (or a suitable semantic
version/date) alongside the existing `@param/`@return/@throws tags so it complies
with the coding guideline.

In
`@src/main/java/io/github/carlos_emr/carlos/encounter/oscarMeasurements/pageUtil/EctSetupMeasurements2Action.java`:
- Around line 70-71: Remove the premature HTML-encoding of the request parameter
in EctSetupMeasurements2Action (the String groupName = Encode.forHtml(...)) so
the raw identifier is used for downstream lookups (EctValidation.getCssPath ->
dao.findByGroupName and EctMeasurementTypesBeanHandler.init ->
mgDao.findByName); instead validate the raw request value at input with an
allowlist pattern for identifier characters and store/propagate the validated
raw groupName, and move context-specific encoding to the view layer (use <c:out
value='${groupName}'/> or Encode.forHtml in AddMeasurementGroup.jsp where
groupName is rendered).

In
`@src/main/java/io/github/carlos_emr/carlos/PMmodule/web/admin/ProgramManagerView2Action.java`:
- Around line 282-286: The code currently normalizes malformed id/clientId to
"0" via ConversionUtils.fromIntString and allows that to flow into
getDependentsList(0) and processAdmission(0,...); instead, validate the raw
parameters from request.getParameter("id") and request.getParameter("clientId")
in ProgramManagerView2Action and reject/bail out on invalid input (e.g., send an
error response or throw an exception) rather than converting to 0. Replace the
String.valueOf(ConversionUtils.fromIntString(...)) usage with explicit
parsing/validation and short-circuit the admission write path (do not call
getDependentsList or processAdmission) when the parameters are missing,
non-numeric, or out of expected range.
- Around line 315-320: The session storage currently HTML-encodes
admission/discharge notes (Encode.forHtml) before saving them in
ProgramManagerView2Action via
request.getSession().setAttribute("admission.dischargeNotes"/"admission.admissionNotes"),
which causes encoded text to persist when override_restriction() reads them and
passes into processAdmission(...); remove the Encode.forHtml wrapping and store
the raw notes in the session (keep
this.setServiceRestriction(e.getRestriction()) as-is), then ensure encoding
happens at render time in the JSP or in the specific display path using the
appropriate OWASP Encoder methods (Encode.forHtml(), Encode.forHtmlAttribute(),
etc.) for the context where the notes are output.
- Around line 122-125: The code currently always wraps
ConversionUtils.fromIntString(request.getParameter("id")) with
String.valueOf(...), which prevents the request.getAttribute("id") fallback from
ever being used; change the logic in ProgramManagerView2Action to first attempt
to read a raw id string from request.getParameter("id"), and only if that is
null or empty use (String)request.getAttribute("id") (as used by
override_restriction() -> view()); then pass that chosen string into
ConversionUtils.fromIntString(...) and finally convert the resulting integer to
a String for programId. Ensure you reference the variable programId, the method
ConversionUtils.fromIntString, request.getParameter("id"), and
request.getAttribute("id") when making the change.

In
`@src/main/java/io/github/carlos_emr/carlos/waitinglist/pageUtil/WLSetupDisplayPatientWaitingList2Action.java`:
- Around line 62-64:
ConversionUtils.fromIntString(request.getParameter("demographic_no")) can return
null so using String.valueOf(parsedDemoNo) yields the literal "null" and will
break lookups; update the logic around parsedDemoNo/demographicNo to check for
null (in WLSetupDisplayPatientWaitingList2Action) and handle it
explicitly—either return an error/redirect or set a safe default—before calling
getDemographic() or instantiating WLPatientWaitingListBeanHandler, ensuring you
don't pass the string "null" into downstream lookups.

In
`@src/main/java/io/github/carlos_emr/carlos/waitinglist/pageUtil/WLSetupDisplayWaitingList2Action.java`:
- Around line 98-101: The code currently normalizes invalid waitingListId to an
empty string but later only checks waitingListId != null, allowing empty IDs to
proceed; in WLSetupDisplayWaitingList2Action, after using
ConversionUtils.fromIntString to parse request.getParameter("waitingListId"),
reject and abort processing (e.g., return an error/redirect or set an explicit
failure state) when parsedWlId <= 0 or the parsed value is empty instead of
assigning "" — update the guarding condition so downstream calls like
WLWaitingListUtil.updateWaitingListRecord(...) and rePositionWaitingList(...)
only run when waitingListId is a valid positive integer (use parsedWlId or
String.valueOf(parsedWlId) for checks).

In `@src/main/webapp/provider/providerupdatepreference.jsp`:
- Around line 113-114: Remove HTML encoding before storing the site identifier
in session: stop using org.owasp.encoder.Encode.forHtml(selected_site) in the
session.setAttribute("site_selected", ...) call and store the raw selected_site
value instead, since encoded values will not match DB queries like
siteDao.getProviderNoBySiteLocation(selectedSite) and
siteDao.getGroupBySiteLocation(selectedSite); ensure any HTML encoding is
performed only at render time when outputting the session value into JSP/HTML.

---

Outside diff comments:
In
`@src/main/java/io/github/carlos_emr/carlos/email/core/EmailAttachmentSettings.java`:
- Around line 64-80: Update the JavaDoc for the public factory method
EmailAttachmentSettings.of(...) to include the required repository policy tags:
add a `@since` tag with the current project version or date, ensure all `@param`
entries for req, fdid, demographicNo, eForms, docs, labs, hrmDocs, forms are
present and accurate, and include the `@return` tag (and `@throws` only if the
method can throw a checked exception); do not add `@author`. Keep the descriptive
text intact and align tagging style with other public methods in the codebase.

---

Duplicate comments:
In `@src/main/java/io/github/carlos_emr/carlos/www/SystemMessage2Action.java`:
- Around line 73-74: In SystemMessage2Action.edit(), Integer.parseInt(messageId)
can throw NumberFormatException for malformed input; wrap the parse and
subsequent systemMessageDao.find(parsedId) call in a try/catch that catches
NumberFormatException and handles it by returning list() (the existing action
path for "missing message") instead of letting the exception propagate; ensure
you reference the edit() method and the systemMessageDao.find(...) call so the
failure branch sets the same response state as the "message not found" flow.

---

Nitpick comments:
In
`@src/main/java/io/github/carlos_emr/carlos/commn/web/DxresearchReport2Action.java`:
- Around line 278-280: The code is HTML-encoding request parameters into
codeSingle/codeSystem before calling codingSystemManager.getCodeDescription(),
which can break lookups; instead obtain the raw parameter values (use
request.getParameter("codesearch") / request.getParameter("codesystem") without
Encode.forHtml), validate/normalize them against allowed coding-system
identifiers or a whitelist, then pass the validated raw values into
codingSystemManager.getCodeDescription(); if you must store or render these
values later, apply Encode.forHtml at output time only (or encode when
persisting to session separately) to avoid breaking the lookup while preserving
XSS protection.

In
`@src/main/java/io/github/carlos_emr/carlos/documentManager/actions/DocumentUpload2Action.java`:
- Around line 130-132: Add an import for
io.github.carlos_emr.carlos.util.ConversionUtils and replace the fully-qualified
call to io.github.carlos_emr.carlos.util.ConversionUtils.fromIntString(queueId)
with ConversionUtils.fromIntString(queueId) in DocumentUpload2Action; ensure the
variable parsedQueueId and the subsequent
request.getSession().setAttribute("preferredQueue",
String.valueOf(parsedQueueId)) remain unchanged and verify that
ConversionUtils.fromIntString handles null/invalid queueId cases (returns a
sensible default or throws) so session storage behavior is consistent with
earlier file operations.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3845c905-4c76-4912-ae04-5c092ff50ee5

📥 Commits

Reviewing files that changed from the base of the PR and between fbb8d7c and cfc948e.

📒 Files selected for processing (19)
  • src/main/java/io/github/carlos_emr/carlos/PMmodule/web/ClientSearchAction22Action.java
  • src/main/java/io/github/carlos_emr/carlos/PMmodule/web/admin/ProgramManagerView2Action.java
  • src/main/java/io/github/carlos_emr/carlos/commn/web/DxresearchReport2Action.java
  • src/main/java/io/github/carlos_emr/carlos/documentManager/actions/AddEditDocument2Action.java
  • src/main/java/io/github/carlos_emr/carlos/documentManager/actions/DocumentUpload2Action.java
  • src/main/java/io/github/carlos_emr/carlos/dxresearch/pageUtil/dxResearchCodeSearch2Action.java
  • src/main/java/io/github/carlos_emr/carlos/dxresearch/pageUtil/dxSetupResearch2Action.java
  • src/main/java/io/github/carlos_emr/carlos/eform/actions/AddEForm2Action.java
  • src/main/java/io/github/carlos_emr/carlos/email/core/EmailAttachmentSettings.java
  • src/main/java/io/github/carlos_emr/carlos/encounter/oscarMeasurements/pageUtil/EctSetupMeasurements2Action.java
  • src/main/java/io/github/carlos_emr/carlos/login/Login2Action.java
  • src/main/java/io/github/carlos_emr/carlos/messenger/pageUtil/MsgViewMessage2Action.java
  • src/main/java/io/github/carlos_emr/carlos/report/reportByTemplate/SQLReporter.java
  • src/main/java/io/github/carlos_emr/carlos/waitinglist/pageUtil/WLSetupDisplayPatientWaitingList2Action.java
  • src/main/java/io/github/carlos_emr/carlos/waitinglist/pageUtil/WLSetupDisplayWaitingList2Action.java
  • src/main/java/io/github/carlos_emr/carlos/www/SystemMessage2Action.java
  • src/main/webapp/annotation/annotation.jsp
  • src/main/webapp/casemgmt/uploadimage.jsp
  • src/main/webapp/provider/providerupdatepreference.jsp

Comment on lines +65 to +74
// Validate demographicNo as a positive integer to break taint chain before session storage
String demographicNo = String.valueOf(ConversionUtils.fromIntString(request.getParameter("demographicNo")));
// Validate providerNo: fall back to trusted logged-in provider; otherwise parse as integer
String providerNoParam = request.getParameter("providerNo");
String providerNo;
if (providerNoParam == null) {
providerNo = loggedInInfo.getLoggedInProviderNo();
} else {
providerNo = String.valueOf(ConversionUtils.fromIntString(providerNoParam));
}

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.

⚠️ Potential issue | 🟠 Major

Don't coerce bad IDs to "0" here.

demographicNo and providerNo are used immediately to build the research handlers and are then persisted into session state. Converting malformed input to "0" switches the action into a bogus patient/provider context instead of rejecting the request or falling back to the logged-in provider.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/io/github/carlos_emr/carlos/dxresearch/pageUtil/dxSetupResearch2Action.java`
around lines 65 - 74, The current code coerces invalid IDs into "0" by calling
String.valueOf(ConversionUtils.fromIntString(...)) which creates a bogus
patient/provider context; change the logic to check the result of
ConversionUtils.fromIntString before converting to String: for demographicNo
call ConversionUtils.fromIntString(request.getParameter("demographicNo")) and if
it returns an invalid/NULL/negative value handle it by rejecting the request
(throwing/returning an error/redirect) instead of using "0"; for providerNo
first check request.getParameter("providerNo") – if null use
loggedInInfo.getLoggedInProviderNo(), otherwise parse with
ConversionUtils.fromIntString and if it’s invalid do not coerce to "0" but treat
it as a validation failure (reject) or explicitly fall back only when you decide
that is acceptable; reference variables/methods: demographicNo, providerNoParam,
providerNo, ConversionUtils.fromIntString, loggedInInfo.getLoggedInProviderNo.

Comment on lines +114 to +117
// Validate demographicNo as integer to break taint chain before session/request storage
String demographic_no = String.valueOf(ConversionUtils.fromIntString(request.getParameter("efmdemographic_no")));
// Encode eform_link to prevent tainted session attribute key
String eform_link = Encode.forHtml(request.getParameter("eform_link"));

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.

⚠️ Potential issue | 🟠 Major

Fail closed when efmdemographic_no is invalid.

fromIntString() turns missing/garbage input into 0, and this action then keeps going through eForm save, attachment linking, PDF generation, and match processing with demographic "0". The previous flow would fail once Integer.valueOf(demographic_no) was reached; this change turns that into silent writes against a bogus demographic.

Comment on lines +105 to +111
Encode.forHtml(req.getParameter("passwordEmail")),
Encode.forHtml(req.getParameter("passwordClueEmail")),
Encode.forHtml(req.getParameter("senderEmail")),
Encode.forHtml(req.getParameter("subjectEmail")),
Encode.forHtml(req.getParameter("bodyEmail")),
Encode.forHtml(req.getParameter("encryptedMessageEmail")),
Encode.forHtml(req.getParameter("emailPatientChartOption"))

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.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "1) Find where EmailAttachmentSettings accessors are consumed"
rg -nP --type=java -C3 '\b(senderEmail|subjectEmail|bodyEmail|encryptedMessageEmail|emailPDFPassword|emailPDFPasswordClue|emailPatientChartOption)\s*\(\)'

echo
echo "2) Detect potential SMTP/header/body sinks"
rg -nP --type=java -C4 '\.(setSubject|setFrom|setText|setContent|addHeader)\s*\([^)]*(senderEmail\(\)|subjectEmail\(\)|bodyEmail\(\)|encryptedMessageEmail\(\))'

echo
echo "3) Detect HTML rendering sinks where forHtml is appropriate"
rg -nP --type=java --type=jsp -C3 '(setAttribute|out\.print|<%=).*?(senderEmail|subjectEmail|bodyEmail|encryptedMessageEmail)'

Repository: carlos-emr/carlos

Length of output: 4110


🏁 Script executed:

# Search for JSP usage of these session/request attributes
rg -n "emailPDFPassword|senderEmail|subjectEmail|bodyEmail|encryptedMessageEmail|emailPatientChartOption" src/main/webapp --type=jsp -B2 -A2

Repository: carlos-emr/carlos

Length of output: 88


🏁 Script executed:

# Check if there are any actual SMTP/mail sending operations in the codebase that use these values
rg -n "MimeMessage|JavaMailSender|Transport\.send|Session\.getInstance" src/main/java --type=java -l | head -20

Repository: carlos-emr/carlos

Length of output: 360


🏁 Script executed:

# Verify JavaDoc for the public method in EmailAttachmentSettings.java
sed -n '60,85p' src/main/java/io/github/carlos_emr/carlos/email/core/EmailAttachmentSettings.java

Repository: carlos-emr/carlos

Length of output: 1115


🏁 Script executed:

# Search for JSP files that might reference these attributes (fd + rg approach)
fd -e jsp . src/main/webapp | head -30 | xargs rg -l "emailPDFPassword|senderEmail|subjectEmail|bodyEmail|encryptedMessageEmail|emailPatientChartOption" 2>/dev/null || echo "No JSP matches found"

Repository: carlos-emr/carlos

Length of output: 81


🏁 Script executed:

# Check if SMTPEmailSender or AsyncMailSender actually consume EmailAttachmentSettings
rg -n "EmailAttachmentSettings|senderEmail\(\)|subjectEmail\(\)|bodyEmail\(\)" src/main/java/io/github/carlos_emr/carlos/service/AsyncMailSender.java src/main/java/io/github/carlos_emr/carlos/email/helpers/SMTPEmailSender.java -A3 -B3

Repository: carlos-emr/carlos

Length of output: 43


🏁 Script executed:

# Get complete JavaDoc and method signature for EmailAttachmentSettings.of()
sed -n '64,95p' src/main/java/io/github/carlos_emr/carlos/email/core/EmailAttachmentSettings.java

Repository: carlos-emr/carlos

Length of output: 1250


🏁 Script executed:

# Check if AddEForm2Action.attachEmailSettings is ever called or if the EmailAttachmentSettings are actually used
rg -n "attachEmailSettings" src/main/java --type=java -B2 -A2

Repository: carlos-emr/carlos

Length of output: 43


🏁 Script executed:

# Search more broadly for any usage of the EmailAttachmentSettings class itself
rg -n "new EmailAttachmentSettings|EmailAttachmentSettings\.of" src/main/java --type=java

Repository: carlos-emr/carlos

Length of output: 649


JavaDoc missing @since tag required per coding guidelines.

The OWASP Encoder import and Encode.forHtml() usage at trust-boundary entry (session storage) is appropriate. The method JavaDoc should include the @since tag per the coding guideline that "All public classes and methods MUST have comprehensive JavaDoc with @param, @return, @throws, and @since tags."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/io/github/carlos_emr/carlos/email/core/EmailAttachmentSettings.java`
around lines 105 - 111, Add a `@since` tag to the JavaDoc for the public method in
class EmailAttachmentSettings that processes the request parameters using
Encode.forHtml (the method invoking Encode.forHtml(req.getParameter(...)) for
passwordEmail, passwordClueEmail, senderEmail, subjectEmail, bodyEmail,
encryptedMessageEmail, emailPatientChartOption); update that method's JavaDoc to
include `@since` with the current project version (or a suitable semantic
version/date) alongside the existing `@param/`@return/@throws tags so it complies
with the coding guideline.

Comment on lines +70 to +71
// Encode groupName to break taint chain before using it in bean construction and session storage
String groupName = Encode.forHtml(request.getParameter("groupName"));

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.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check how groupName is used in EctValidation and EctMeasurementTypesBeanHandler
ast-grep --pattern $'class EctValidation {
  $$$
  getCssPath($$$) {
    $$$
  }
  $$$
}'

ast-grep --pattern $'class EctMeasurementTypesBeanHandler {
  $$$
  EctMeasurementTypesBeanHandler($_, $_) {
    $$$
  }
  $$$
}'

Repository: carlos-emr/carlos

Length of output: 43


🏁 Script executed:

#!/bin/bash
# Find the files containing these classes
find . -type f -name "*.java" | xargs grep -l "class EctValidation"
find . -type f -name "*.java" | xargs grep -l "class EctMeasurementTypesBeanHandler"
find . -type f -name "EctSetupMeasurements2Action.java"

Repository: carlos-emr/carlos

Length of output: 596


🏁 Script executed:

#!/bin/bash
# Read EctSetupMeasurements2Action.java to trace groupName flow
wc -l "./src/main/java/io/github/carlos_emr/carlos/encounter/oscarMeasurements/pageUtil/EctSetupMeasurements2Action.java"
head -100 "./src/main/java/io/github/carlos_emr/carlos/encounter/oscarMeasurements/pageUtil/EctSetupMeasurements2Action.java" | tail -40

Repository: carlos-emr/carlos

Length of output: 2321


🏁 Script executed:

#!/bin/bash
# Read EctValidation.java to see getCssPath implementation
wc -l "./src/main/java/io/github/carlos_emr/carlos/encounter/oscarMeasurements/pageUtil/EctValidation.java"
cat -n "./src/main/java/io/github/carlos_emr/carlos/encounter/oscarMeasurements/pageUtil/EctValidation.java" | head -150

Repository: carlos-emr/carlos

Length of output: 6226


🏁 Script executed:

#!/bin/bash
# Search for getCssPath method in EctValidation.java
grep -n "getCssPath" "./src/main/java/io/github/carlos_emr/carlos/encounter/oscarMeasurements/pageUtil/EctValidation.java"

Repository: carlos-emr/carlos

Length of output: 118


🏁 Script executed:

#!/bin/bash
# Read the getCssPath method implementation
sed -n '239,260p' "./src/main/java/io/github/carlos_emr/carlos/encounter/oscarMeasurements/pageUtil/EctValidation.java"

Repository: carlos-emr/carlos

Length of output: 1530


🏁 Script executed:

#!/bin/bash
# Read more of the getCssPath method
sed -n '239,290p' "./src/main/java/io/github/carlos_emr/carlos/encounter/oscarMeasurements/pageUtil/EctValidation.java"

Repository: carlos-emr/carlos

Length of output: 2614


🏁 Script executed:

#!/bin/bash
# Read EctMeasurementTypesBeanHandler to see what it does with groupName
wc -l "./src/main/java/io/github/carlos_emr/carlos/encounter/oscarMeasurements/bean/EctMeasurementTypesBeanHandler.java"
head -80 "./src/main/java/io/github/carlos_emr/carlos/encounter/oscarMeasurements/bean/EctMeasurementTypesBeanHandler.java"

Repository: carlos-emr/carlos

Length of output: 3438


🏁 Script executed:

#!/bin/bash
# Find the init(groupName, demo) method
grep -n "public boolean init(String groupName" "./src/main/java/io/github/carlos_emr/carlos/encounter/oscarMeasurements/bean/EctMeasurementTypesBeanHandler.java"

Repository: carlos-emr/carlos

Length of output: 120


🏁 Script executed:

#!/bin/bash
# Read the init(groupName, demo) method
sed -n '95,160p' "./src/main/java/io/github/carlos_emr/carlos/encounter/oscarMeasurements/bean/EctMeasurementTypesBeanHandler.java"

Repository: carlos-emr/carlos

Length of output: 3105


🏁 Script executed:

#!/bin/bash
# Verify if there are any tests that would catch this functional break
find . -type f -name "*EctSetupMeasurements2ActionTest*" -o -name "*Test*.java" | xargs grep -l "EctSetupMeasurements2Action" 2>/dev/null

Repository: carlos-emr/carlos

Length of output: 45


🏁 Script executed:

#!/bin/bash
# Check if there are any example/valid groupName values in the codebase to understand the format
rg "groupName\s*=" --type java -A 2 | head -40

Repository: carlos-emr/carlos

Length of output: 3933


🏁 Script executed:

#!/bin/bash
# Check if groupName values in database might contain special characters
rg "setGroupName|new MeasurementGroup" --type java -A 1 -B 1 | head -50

Repository: carlos-emr/carlos

Length of output: 5055


🏁 Script executed:

#!/bin/bash
# Double-check if groupName might ever be output to HTML in the JSP
grep -r "groupName" src/main/webapp/encounter/oscarMeasurements/ --include="*.jsp" 2>/dev/null | head -20

Repository: carlos-emr/carlos

Length of output: 3232


🏁 Script executed:

#!/bin/bash
# Check if AddMeasurementGroup.jsp properly encodes groupName before output
cat -n "src/main/webapp/encounter/oscarMeasurements/AddMeasurementGroup.jsp" | grep -A 2 -B 2 "groupName"

Repository: carlos-emr/carlos

Length of output: 1504


🏁 Script executed:

#!/bin/bash
# Check if any of the JSPs use Encode.forHtml or c:out for groupName
rg "Encode.forHtml.*groupName|c:out.*groupName" src/main/webapp/encounter/oscarMeasurements/ --include="*.jsp"

Repository: carlos-emr/carlos

Length of output: 502


🏁 Script executed:

#!/bin/bash
# Check if any of the JSPs use Encode.forHtml or c:out for groupName
rg "Encode.forHtml.*groupName|c:out.*groupName" src/main/webapp/encounter/oscarMeasurements/ -t jsp

Repository: carlos-emr/carlos

Length of output: 88


Remove HTML encoding from groupName at input; apply context-specific encoding only at output.

Encode.forHtml() converts special characters (e.g., & to &amp;) and should only be applied when outputting to HTML contexts. Applying it here before database operations breaks downstream lookups: EctValidation.getCssPath() calls dao.findByGroupName(inputGroupName) and EctMeasurementTypesBeanHandler.init() calls mgDao.findByName(groupName). If a groupName in the database is "Test&Unit", encoding it before the query causes the lookup to fail.

Instead, validate the input at the boundary (using allowlist pattern for identifier characters), then apply Encode.forHtml() only in JSPs where groupName is output (AddMeasurementGroup.jsp lines 97, 101–103, 135, etc.) using <c:out value='${groupName}'/> or Encode.forHtml in the JSP context.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/io/github/carlos_emr/carlos/encounter/oscarMeasurements/pageUtil/EctSetupMeasurements2Action.java`
around lines 70 - 71, Remove the premature HTML-encoding of the request
parameter in EctSetupMeasurements2Action (the String groupName =
Encode.forHtml(...)) so the raw identifier is used for downstream lookups
(EctValidation.getCssPath -> dao.findByGroupName and
EctMeasurementTypesBeanHandler.init -> mgDao.findByName); instead validate the
raw request value at input with an allowlist pattern for identifier characters
and store/propagate the validated raw groupName, and move context-specific
encoding to the view layer (use <c:out value='${groupName}'/> or Encode.forHtml
in AddMeasurementGroup.jsp where groupName is rendered).

Comment on lines 122 to 125
// find the program id; parse as integer to validate and break taint chain before session storage
String programId = String.valueOf(
io.github.carlos_emr.carlos.util.ConversionUtils.fromIntString(request.getParameter("id")));

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.

⚠️ Potential issue | 🟠 Major

Preserve the request-attribute fallback for programId.

String.valueOf(...) never returns null, so Line 133's request.getAttribute("id") fallback is now dead. Paths like override_restriction() that forward back into view() via request attributes can now load program "0" instead of the intended program.

Suggested fix
-        String programId = String.valueOf(
-                io.github.carlos_emr.carlos.util.ConversionUtils.fromIntString(request.getParameter("id")));
+        String programId = null;
+        String programIdParam = request.getParameter("id");
+        if (programIdParam != null) {
+            int parsedProgramId =
+                    io.github.carlos_emr.carlos.util.ConversionUtils.fromIntString(programIdParam);
+            if (parsedProgramId > 0) {
+                programId = String.valueOf(parsedProgramId);
+            }
+        }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/io/github/carlos_emr/carlos/PMmodule/web/admin/ProgramManagerView2Action.java`
around lines 122 - 125, The code currently always wraps
ConversionUtils.fromIntString(request.getParameter("id")) with
String.valueOf(...), which prevents the request.getAttribute("id") fallback from
ever being used; change the logic in ProgramManagerView2Action to first attempt
to read a raw id string from request.getParameter("id"), and only if that is
null or empty use (String)request.getAttribute("id") (as used by
override_restriction() -> view()); then pass that chosen string into
ConversionUtils.fromIntString(...) and finally convert the resulting integer to
a String for programId. Ensure you reference the variable programId, the method
ConversionUtils.fromIntString, request.getParameter("id"), and
request.getAttribute("id") when making the change.

Comment on lines +282 to +286
// Validate programId and clientId as integers to break taint chain
String programId = String.valueOf(
io.github.carlos_emr.carlos.util.ConversionUtils.fromIntString(request.getParameter("id")));
String clientId = String.valueOf(
io.github.carlos_emr.carlos.util.ConversionUtils.fromIntString(request.getParameter("clientId")));

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.

⚠️ Potential issue | 🟠 Major

Reject invalid id / clientId before the admission write path.

These two conversions now collapse bad input to "0" and then flow into getDependentsList(0) and processAdmission(0, ...). This path mutates admission state, so malformed requests should be rejected instead of being normalized into a sentinel ID.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/io/github/carlos_emr/carlos/PMmodule/web/admin/ProgramManagerView2Action.java`
around lines 282 - 286, The code currently normalizes malformed id/clientId to
"0" via ConversionUtils.fromIntString and allows that to flow into
getDependentsList(0) and processAdmission(0,...); instead, validate the raw
parameters from request.getParameter("id") and request.getParameter("clientId")
in ProgramManagerView2Action and reject/bail out on invalid input (e.g., send an
error response or throw an exception) rather than converting to 0. Replace the
String.valueOf(ConversionUtils.fromIntString(...)) usage with explicit
parsing/validation and short-circuit the admission write path (do not call
getDependentsList or processAdmission) when the parameters are missing,
non-numeric, or out of expected range.

Comment on lines +315 to +320
// store this for display; encode free-text notes to break taint chain before session storage
this.setServiceRestriction(e.getRestriction());

request.getSession().setAttribute("programId", programId);
request.getSession().setAttribute("admission.dischargeNotes", dischargeNotes);
request.getSession().setAttribute("admission.admissionNotes", admissionNotes);
request.getSession().setAttribute("admission.dischargeNotes", Encode.forHtml(dischargeNotes));
request.getSession().setAttribute("admission.admissionNotes", Encode.forHtml(admissionNotes));

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.

⚠️ Potential issue | 🟠 Major

Don't HTML-encode notes before storing them for the override flow.

override_restriction() reads these session values back and passes them into processAdmission(...), so encoding here will persist &lt;, &amp;, etc. into admission/discharge notes whenever the override path is used. Encode on the JSP/rendering path instead, or keep separate display-only attributes. As per coding guidelines, use context-appropriate OWASP Encoder methods for user input output: Encode.forHtml() for HTML body, Encode.forHtmlAttribute() for HTML attributes, Encode.forJavaScript() for JS contexts, Encode.forJavaScriptAttribute() for JS in HTML attributes, Encode.forCssString() for CSS, Encode.forUri()/Encode.forUriComponent() for URLs.

Suggested fix
-            request.getSession().setAttribute("admission.dischargeNotes", Encode.forHtml(dischargeNotes));
-            request.getSession().setAttribute("admission.admissionNotes", Encode.forHtml(admissionNotes));
+            request.getSession().setAttribute("admission.dischargeNotes", dischargeNotes);
+            request.getSession().setAttribute("admission.admissionNotes", admissionNotes);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/io/github/carlos_emr/carlos/PMmodule/web/admin/ProgramManagerView2Action.java`
around lines 315 - 320, The session storage currently HTML-encodes
admission/discharge notes (Encode.forHtml) before saving them in
ProgramManagerView2Action via
request.getSession().setAttribute("admission.dischargeNotes"/"admission.admissionNotes"),
which causes encoded text to persist when override_restriction() reads them and
passes into processAdmission(...); remove the Encode.forHtml wrapping and store
the raw notes in the session (keep
this.setServiceRestriction(e.getRestriction()) as-is), then ensure encoding
happens at render time in the JSP or in the specific display path using the
appropriate OWASP Encoder methods (Encode.forHtml(), Encode.forHtmlAttribute(),
etc.) for the context where the notes are output.

Comment on lines +62 to +64
// Validate demographicNo as a positive integer to break taint chain before session storage
Integer parsedDemoNo = ConversionUtils.fromIntString(request.getParameter("demographic_no"));
String demographicNo = String.valueOf(parsedDemoNo);

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.

⚠️ Potential issue | 🟡 Minor

Handle null return from ConversionUtils.fromIntString().

ConversionUtils.fromIntString() returns null for invalid/missing input. String.valueOf(null) produces the literal string "null", which would be passed to getDemographic() and WLPatientWaitingListBeanHandler, likely causing lookup failures or exceptions.

Consider adding a null check with a sensible default or error response:

🛡️ Proposed fix to handle null
         // Validate demographicNo as a positive integer to break taint chain before session storage
         Integer parsedDemoNo = ConversionUtils.fromIntString(request.getParameter("demographic_no"));
+        if (parsedDemoNo == null || parsedDemoNo <= 0) {
+            throw new RuntimeException("Invalid demographic_no parameter");
+        }
         String demographicNo = String.valueOf(parsedDemoNo);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/io/github/carlos_emr/carlos/waitinglist/pageUtil/WLSetupDisplayPatientWaitingList2Action.java`
around lines 62 - 64,
ConversionUtils.fromIntString(request.getParameter("demographic_no")) can return
null so using String.valueOf(parsedDemoNo) yields the literal "null" and will
break lookups; update the logic around parsedDemoNo/demographicNo to check for
null (in WLSetupDisplayPatientWaitingList2Action) and handle it
explicitly—either return an error/redirect or set a safe default—before calling
getDemographic() or instantiating WLPatientWaitingListBeanHandler, ensuring you
don't pass the string "null" into downstream lookups.

Comment on lines +98 to +101
if (request.getParameter("waitingListId") != null) {
waitingListId = request.getParameter("waitingListId");
// Validate waitingListId as an integer to break taint chain before session storage
int parsedWlId = ConversionUtils.fromIntString(request.getParameter("waitingListId"));
waitingListId = parsedWlId > 0 ? String.valueOf(parsedWlId) : "";

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.

⚠️ Potential issue | 🟠 Major

Reject invalid waitingListId before continuing.

This block normalizes bad input to "", but the update path later only checks waitingListId != null, so malformed requests can still reach WLWaitingListUtil.updateWaitingListRecord(...) / rePositionWaitingList(...) with an empty ID instead of failing closed.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/io/github/carlos_emr/carlos/waitinglist/pageUtil/WLSetupDisplayWaitingList2Action.java`
around lines 98 - 101, The code currently normalizes invalid waitingListId to an
empty string but later only checks waitingListId != null, allowing empty IDs to
proceed; in WLSetupDisplayWaitingList2Action, after using
ConversionUtils.fromIntString to parse request.getParameter("waitingListId"),
reject and abort processing (e.g., return an error/redirect or set an explicit
failure state) when parsedWlId <= 0 or the parsed value is empty instead of
assigning "" — update the guarding condition so downstream calls like
WLWaitingListUtil.updateWaitingListRecord(...) and rePositionWaitingList(...)
only run when waitingListId is a valid positive integer (use parsedWlId or
String.valueOf(parsedWlId) for checks).

Comment on lines +113 to +114
// Encode site value to break taint chain before session storage
session.setAttribute("site_selected", ("none".equals(selected_site) ? null : org.owasp.encoder.Encode.forHtml(selected_site)));

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.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check how site_selected session attribute is used downstream
rg -n "site_selected" --type=jsp --type=java -C3 | head -50

Repository: carlos-emr/carlos

Length of output: 88


🏁 Script executed:

rg "site_selected" -C3

Repository: carlos-emr/carlos

Length of output: 2473


🏁 Script executed:

# Search specifically for getAttribute calls on site_selected
rg "getAttribute.*site_selected|site_selected.*getAttribute" -C3

Repository: carlos-emr/carlos

Length of output: 1484


🏁 Script executed:

# Also search the file being reviewed to understand context better
cat -n src/main/webapp/provider/providerupdatepreference.jsp | head -130 | tail -30

Repository: carlos-emr/carlos

Length of output: 2008


🏁 Script executed:

# Look at appointmentprovideradminday.jsp to see how selectedSite is used after retrieval
rg -A 10 "get site providers list" src/main/webapp/provider/appointmentprovideradminday.jsp

Repository: carlos-emr/carlos

Length of output: 723


🏁 Script executed:

# Also check the full context of selectedSite usage in appointmentprovideradminday.jsp
sed -n '1,100p' src/main/webapp/provider/appointmentprovideradminday.jsp | grep -n "selectedSite\|siteDao\|site"

Repository: carlos-emr/carlos

Length of output: 43


🏁 Script executed:

# Check if site identifiers typically contain special characters
rg "getProviderNoBySiteLocation|getGroupBySiteLocation" --type=java -B5 -A5 | head -40

Repository: carlos-emr/carlos

Length of output: 3830


🏁 Script executed:

# Look at the actual SiteDao implementation to understand the lookup
fd -e java -path "*/SiteDao*" | xargs cat | head -100

Repository: carlos-emr/carlos

Length of output: 229


🏁 Script executed:

# Find SiteDao implementation file
find . -name "*SiteDao*.java" -type f

Repository: carlos-emr/carlos

Length of output: 524


🏁 Script executed:

# Look for getProviderNoBySiteLocation implementation
rg "getProviderNoBySiteLocation" --type=java -A8

Repository: carlos-emr/carlos

Length of output: 3969


🏁 Script executed:

# Check SiteDaoImpl to see the full implementation
cat src/main/java/io/github/carlos_emr/carlos/commn/dao/SiteDaoImpl.java | grep -A10 "getProviderNoBySiteLocation\|getGroupBySiteLocation"

Repository: carlos-emr/carlos

Length of output: 1221


🏁 Script executed:

# Check if there are any example site names or constraints on what site.name can be
rg "site.name|site_name" src/main/java/io/github/carlos_emr/carlos/commn/model/ -B2 -A2 | head -50

Repository: carlos-emr/carlos

Length of output: 1088


Remove Encode.forHtml() from session storage—encoding before database lookups breaks site identifier matching.

The value is stored with HTML encoding (Encode.forHtml()) but then passed to siteDao.getProviderNoBySiteLocation(selectedSite) and siteDao.getGroupBySiteLocation(selectedSite), which query where s.name = ?1 against the database. If a site name contains special characters (e.g., "Town&Country"), the encoded value ("Town&amp;Country") will not match the database record, causing the lookup to fail silently.

Encoding should be applied at output time (when rendering HTML), not at storage time. Store the raw site identifier in the session and apply Encode.forHtml() only when displaying the value in HTML markup. Alternatively, verify that site names are constrained to alphanumeric characters with no special characters that require HTML encoding.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/webapp/provider/providerupdatepreference.jsp` around lines 113 -
114, Remove HTML encoding before storing the site identifier in session: stop
using org.owasp.encoder.Encode.forHtml(selected_site) in the
session.setAttribute("site_selected", ...) call and store the raw selected_site
value instead, since encoded values will not match DB queries like
siteDao.getProviderNoBySiteLocation(selectedSite) and
siteDao.getGroupBySiteLocation(selectedSite); ensure any HTML encoding is
performed only at render time when outputting the session value into JSP/HTML.

@yingbull

yingbull commented Apr 5, 2026

Copy link
Copy Markdown
Collaborator

@codex review
@SourceryAI review

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

Signed-off-by: Michael Yingbull <michael@maplecreekmedical.ca>
@github-actions

github-actions Bot commented Apr 5, 2026

Copy link
Copy Markdown
Contributor

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Snapshot Warnings

⚠️: No snapshots were found for the head SHA f0680ee.
Ensure that dependencies are being submitted on PR branches and consider enabling retry-on-snapshot-warnings. See the documentation for more information and troubleshooting advice.

Scanned Files

None

if ("inbox".equals(from) || "sent".equals(from) || "trash".equals(from) || "messenger".equals(from)) {
validatedFrom = from;
}
request.getSession().setAttribute("from", validatedFrom);

Check notice

Code scanning / SnykCode

Trust Boundary Violation Note

Unsanitized input from {0} {1} into {2} where it is used to modify the HTTP session object. This could result in mixing trusted and untrusted data in the same data structure, thus increasing the likelihood to mistakenly trust unvalidated data.
String orderKey = orderBy.startsWith("!") ? orderBy.substring(1) : orderBy;
if ("status".equals(orderKey) || "from".equals(orderKey) || "subject".equals(orderKey)
|| "date".equals(orderKey) || "sentto".equals(orderKey) || "linked".equals(orderKey)) {
request.getSession().setAttribute("orderBy", orderBy);

Check notice

Code scanning / SnykCode

Trust Boundary Violation Note

Unsanitized input from {0} {1} into {2} where it is used to modify the HTTP session object. This could result in mixing trusted and untrusted data in the same data structure, thus increasing the likelihood to mistakenly trust unvalidated data.
@yingbull yingbull closed this Apr 5, 2026
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.

sec: Fix 64 trust boundary violations across 18 files — unsanitized HTTP params stored in session

4 participants