Skip to content

Application tech debt

This register lists 14 findings: 3 high, 7 medium, 3 low and 1 informational. There are no critical findings. Findings whose impact depends on API behavior that could not be traced are marked **.

Findings summary

ID Severity Title
TD-APP-001 HIGH Anti-forgery validation disabled on all POST handlers
TD-APP-002 HIGH Developer-access handler escalates capability flags
TD-APP-003 HIGH No server-side role check on state-changing handlers
TD-APP-004 MEDIUM CanPrint is computed but never enforced
TD-APP-005 MEDIUM Audit user name is client-supplied
TD-APP-006 MEDIUM Pay-online maximum and policy number are client-supplied
TD-APP-007 MEDIUM Delete confirmation form lacks a POST method
TD-APP-008 MEDIUM Unvalidated date parsing and server-side window not enforced
TD-APP-009 MEDIUM Pay by mail and download statement drop the last PDF byte
TD-APP-010 MEDIUM Sync-over-async call in the page model constructor
TD-APP-011 LOW Development environment, permissive CORS and disabled SSL setting
TD-APP-012 LOW No model validation
TD-APP-013 LOW Dead and orphaned code
TD-APP-014 INFO Package versions lag the feed

TD-APP-001

Severity HIGH. [IgnoreAntiforgeryToken] on the page model, and on BolMenuModel †, disables anti-forgery validation for all 12 POST handlers, eight of them state-changing (BR-APP-006). Impact: cross-site request forgery can update claims, override due dates, delete statements and create payment requests using the victim's Windows credentials. Recommendation: remove the attribute and send the anti-forgery token from ClaimsTable.js and PaymentModal.js in a RequestVerificationToken header. Raise the base-class behavior with the BolMiddleware owners. Evidence: Pages/NDReimbursement.cshtml.cs line 10, ClaimsTable.js line 233, PaymentModal.js line 29.

TD-APP-002

Severity HIGH. The developer-access handler is routable by direct POST with no IT or QA check, and PolicyHolder or DueDate forces an updater flag to true (BR-APP-005). Impact: any authorized user, including a read-only user, can escalate to updater capabilities in the UI flags. The effect on updates is limited by the API**, because the other handlers do not check the flags. Recommendation: remove the handler and DevAccessType, or restrict it to IsInternalITUser with a server-side check and a non-production flag.

TD-APP-003

Severity HIGH. Override, delete and download rely on the view hiding controls. The due-date and delete handlers check no role, and the update, pay-by-mail and pay-online handlers do not check the updater roles (BR-APP-003). Impact: a read-only or external user can POST to internal-only handlers directly, because the page gate admits all four roles (BR-APP-001). Recommendation: enforce IsInternalUpdater or IsExternalUpdater in each handler, or use per-handler SecurityApiAuthorize, and return 403.

TD-APP-004

Severity MEDIUM. CanPrint (role DocCoreApiUserResource) is computed but never enforced on the download handler. Impact: any page-level user can download the statement PDF. Recommendation: check CanPrint in the download and pay-by-mail handlers and verify that the statement belongs to the policy in context.

TD-APP-005

Severity MEDIUM. The audit user (UpdateUser) comes from the client-supplied UserName. Impact: the audit trail can be forged. Recommendation: use CurrentUserId on the server.

TD-APP-006

Severity MEDIUM. Pay online validates the total against a client-supplied maxAmount, and policyNum is read from a client-side hidden field (BR-SCR-007). Impact: the client can bypass the limit or pay against another policy**. Recommendation: recompute the maximum and policy from the server-side statement.

TD-APP-007

Severity MEDIUM. The delete-confirmation form has no method="post". The form submits GET; the only delete handler is OnPostDeleteStatement (no OnGetDeleteStatement), so the form cannot invoke it, and a script function that would perform the delete is never called. Impact: deletion cannot be performed from the UI (the HTTP result of the unmatched GET is unspecified**); the handler is reachable only by a separately issued POST. Recommendation: add method="post" with a token (see TD-APP-001) and remove the dead script.

TD-APP-008

Severity MEDIUM. The due-date handler uses DateTime.Parse on raw form input with no culture or validation. The 90-day window is not enforced on the server (BR-SCR-002), and the minimum and maximum override dates are not zero-padded. Impact: wrong dates or exceptions, and out-of-window overrides. Recommendation: use DateTime.TryParseExact with an invariant culture and re-check the window on the server.

TD-APP-009

Severity MEDIUM. Both OnPostPayByMail and OnPostDownloadStatement write Preview.Length - 1 bytes to the response, which drops the final byte of the PDF. Impact: the statement PDF returned by either handler may be corrupt or truncated. Recommendation: write the whole buffer (Preview.Length bytes) in both handlers and add a test for each.

TD-APP-010

Severity MEDIUM. The constructor calls IsAuthorizedAsync call followed by .Result. Impact: thread-pool starvation and deadlock risk. Recommendation: move the call into an async lifecycle hook.

TD-APP-011

Severity LOW. web.config hard-codes ASPNETCORE_ENVIRONMENT=Development and permissive CORS headers (Access-Control-Allow-Credentials: true, origin http://localhost). appsettings.json sets Ssl:Disabled to "true". No secrets are committed. Impact: development behavior may reach deployed hosts. Recommendation: set the environment per stage in the pipeline, remove the CORS headers and make the SSL setting per environment.

TD-APP-012

Severity LOW. No handler checks ModelState or validates input, and raw form keys are read directly. Impact: malformed input reaches the API. Recommendation: add validation.

TD-APP-013

Severity LOW. Dead and orphaned code: a duplicate jQuery 3.6.0 from a public CDN, a malformed click binding in NDReimbursementWebApp.js, a dead delete script, ViewDocument.js, SaifDropdown.js, an empty site.js, _ValidationScriptsPartial, the orphan _MakePaymentModalBase, unused PayOnlineApp and PayOnlinePage, commented-out start-up code, and stale sass-kendo and legacy stylesheet build configuration. Impact: maintenance cost and supply-chain exposure. Recommendation: remove the dead code, use one jQuery and pin or self-host scripts. The claim profile link in the view uses a legacy page extension hard-coded to another application.

TD-APP-014

Severity INFO. BolMiddleware 2.0.25309.3 and four API clients lag the feed (BolMiddleware 2.2026.929.1, DigitalPaymentAPIClient 6.2026.610.1, NDReimbursementAPI.Client 1.2026.413.1). Impact: missing package fixes**, in particular for the cookie risks in INH-008. Recommendation: plan an upgrade and a regression test.

Note: Statements marked with † are derived from dependency library documentation via the Legends CLI. Statements marked with ** could not be confirmed; treat as unknown until verified.

Sources

  • src/NDReimbursementWebApp/Pages/NDReimbursement.cshtml.cs
  • src/NDReimbursementWebApp/Pages/NDReimbursement.cshtml
  • src/NDReimbursementWebApp/wwwroot/js/ClaimsTable.js
  • src/NDReimbursementWebApp/wwwroot/js/PaymentModal.js
  • src/NDReimbursementWebApp/wwwroot/js/NDReimbursementWebApp.js
  • src/NDReimbursementWebApp/web.config
  • src/NDReimbursementWebApp/appsettings.json
  • src/NDReimbursementWebApp/NDReimbursementWebApp.csproj