Skip to content

fix(auth): close the two open CodeQL alerts in the Vue app - #312

Open
rlorenzo wants to merge 3 commits into
mainfrom
fix/codeql-sendbackto-redirect
Open

fix(auth): close the two open CodeQL alerts in the Vue app#312
rlorenzo wants to merge 3 commits into
mainfrom
fix/codeql-sendbackto-redirect

Conversation

@rlorenzo

@rlorenzo rlorenzo commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Closes CodeQL alerts 765 and 768. Alerts 766/767 were dismissed as false positives: only the filter values come from route.query, the keys are always caller-supplied literals.

Changes

765 js/user-controlled-bypassgetLoginUrl wrapped an always-true route.fullPath.length >= 0 check around two identical branches. It guarded nothing; it existed only to fake a reactive dependency, since getCurrentPath() read the non-reactive globalThis.location. Now derives the return path from route.fullPath, with base prefixing shared via withApplicationBase().

768 js/remote-property-injectionCtsHome carried its own copy of the post-login redirect, and the copy skipped the isValidInternalPath guard. Now calls the shared helper, which builds the query with Object.fromEntries so a __proto__ key stays own data.

Redirect loop (found while testing) — the guard called the redirect helper with useRoute(), the route being navigated away from, so a pending sendBackTo navigation re-fired and cancelled itself. Measured on main: 248 cancelled navigations in ~1.5s. Fixed by dropping the guard call site, since the landing page already owns the redirect.

Verified in browser

Emulated user holding SVMSecure.CTS.Students, loading /CTS/Home?sendBackTo=<target> against each file set in turn:

target main this PR
/CTS/MyAssessments infinite cancelled-navigation loop lands on My Assessments
…?tab=epa&view=list same loop lands, query intact
https://evil.example/steal pushes to /CTS/https://evil.example/steal, 404 rejected, CTS home renders
//evil.example/steal pushes to //evil.example/steal, 404 rejected, CTS home renders

Not an open redirect on main: location.host stayed local in both hostile cases, because vue-router resolves the value as an in-app path, not a URL.

For reviewers

  • Behavior change: the six other areas sharing useRequireLogin lose the guard-level sendBackTo redirect. It looped for them too, and nothing in VIPER 1 or VIPER 2 generates those links.
  • Behavior change: CtsHome's login ReturnUrl is now the current path, not a hardcoded /CTS/, so a deep link survives the sign-in round trip.
  • /CTS/ serves the legacy Razor page (CTSController.Index claims /[area]), so the SPA deep link only works from /CTS/Home.
  • CodeQL scans main, so 765/768 stay open through the Development/TEST leg.

Testing

1134 frontend tests pass, 13 new in require-login.test.ts (rejected targets, query parsing, __proto__, base handling). verify:build and vue-tsc green. Also drove the live Vite-served module in the browser: all 8 redirect cases matched the unit tests.

@codecov-commenter

codecov-commenter commented Aug 17, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 75.00000% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 41.79%. Comparing base (21551ff) to head (5b681db).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
VueApp/src/composables/RequireLogin.ts 75.00% 2 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #312      +/-   ##
==========================================
+ Coverage   41.74%   41.79%   +0.04%     
==========================================
  Files         992      992              
  Lines       49697    49684      -13     
  Branches     5854     5851       -3     
==========================================
+ Hits        20748    20763      +15     
+ Misses      28038    28007      -31     
- Partials      911      914       +3     
Flag Coverage Δ
backend 39.80% <ø> (ø)
frontend 58.58% <75.00%> (+0.42%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
VueApp/src/composables/RequireLogin.ts 31.66% <75.00%> (+26.18%) ⬆️

@codecov-commenter

codecov-commenter commented Aug 17, 2026

Copy link
Copy Markdown

Bundle Report

Changes will increase total bundle size by 3.18kB (0.14%) ⬆️. This is within the configured threshold ✅

Detailed changes
Bundle name Size Change
viper-frontend-esm 2.29MB 3.18kB (0.14%) ⬆️

Affected Assets, Files, and Routes:

view changes for bundle: viper-frontend-esm

Assets Changed:

Asset Name Size Change Total Size Change (%)
assets/quasar.client-*.js (New) 475.39kB 475.39kB 100.0% 🚀
assets/schedule-*.js 72 bytes 55.02kB 0.13%
assets/TermManagement-*.js 86 bytes 52.46kB 0.16%
assets/SortableList-*.js -3 bytes 45.53kB -0.01%
assets/GenericError-*.js -486.94kB 44.59kB -91.61%
assets/CourseDetail-*.js 41 bytes 39.4kB 0.1%
assets/PhotoGallery-*.js 26 bytes 36.15kB 0.07%
assets/InstructorEdit-*.js 76 bytes 28.67kB 0.27%
assets/InstructorList-*.js 116 bytes 26.07kB 0.45%
assets/StaffDashboard-*.js 91 bytes 25.6kB 0.36%
assets/effort-*.js 123 bytes 23.77kB 0.52%
assets/effort-*.js -2 bytes 988 bytes -0.2%
assets/Files-*.js 30 bytes 22.57kB 0.13%
assets/CrossListedCoursesSection-*.js 9 bytes 22.3kB 0.04%
assets/ContentBlockEdit-*.js 136 bytes 20.77kB 0.66%
assets/MultiYearReport-*.js -3 bytes 18.8kB -0.02%
assets/EmergencyContactForm-*.js 29 bytes 17.23kB 0.17%
assets/AuditList-*.js 37 bytes 5.16kB 0.72%
assets/AuditList-*.js 36 bytes 17.1kB 0.21%
assets/MyAssessments-*.js 41 bytes 16.56kB 0.25%
assets/CourseList-*.js 33 bytes 15.93kB 0.21%
assets/EffortTypeList-*.js 49 bytes 15.4kB 0.32%
assets/ManageLinkCollections-*.js 93 bytes 15.3kB 0.61%
assets/runtime-*.esm-bundler-DpvtzK0D.js (New) 13.45kB 13.45kB 100.0% 🚀
assets/CmsHome-*.js 47 bytes 11.42kB 0.41%
assets/AuditLogPage-*.js -3 bytes 11.26kB -0.03%
assets/ViperFetch-*.js (New) 11.17kB 11.17kB 100.0% 🚀
assets/EmergencyContactList-*.js 8 bytes 11.07kB 0.07%
assets/CourseImportDialog-*.js 55 bytes 10.88kB 0.51%
assets/permission-*.js 33 bytes 9.78kB 0.34%
assets/CourseLinkDialog-*.js -2 bytes 9.37kB -0.02%
assets/ManageBundleCompetencies-*.js 37 bytes 8.9kB 0.42%
assets/ReportFilterForm-*.js -2 bytes 8.86kB -0.02%
assets/LeftNavEdit-*.js 133 bytes 8.81kB 1.53%
assets/StudentClassYear-*.js 36 bytes 8.49kB 0.43%
assets/cts-*.js 125 bytes 8.45kB 1.5%
assets/MyEffort-*.js -2 bytes 8.21kB -0.02%
assets/LeftNavMenus-*.js 38 bytes 8.04kB 0.47%
assets/ImportFiles-*.js 87 bytes 7.7kB 1.14%
assets/EmergencyContactView-*.js 1 bytes 7.61kB 0.01%
assets/ContentBlocks-*.js 36 bytes 7.59kB 0.48%
assets/ManageSessionCompetencies-*.js 37 bytes 6.87kB 0.54%
assets/AssessmentList-*.js 37 bytes 6.85kB 0.54%
assets/ManageCompetencies-*.js 35 bytes 6.65kB 0.53%
assets/ContentBlockHistory-*.js 38 bytes 6.59kB 0.58%
assets/UnitList-*.js -4 bytes 6.34kB -0.06%
assets/WebReports-*.js 93 bytes 6.12kB 1.54%
assets/CompetenciesBundleReport-*.js 36 bytes 6.11kB 0.59%
assets/use-*.js 43 bytes 6.05kB 0.72%
assets/use-*.js 1 bytes 377 bytes 0.27%
assets/use-*.js 1 bytes 664 bytes 0.15%
assets/use-*.js 39 bytes 888 bytes 4.59%
assets/use-*.js -12 bytes 5.38kB -0.22%
assets/AssessmentEpa-*.js 94 bytes 5.74kB 1.66%
assets/BulkEncrypt-*.js 35 bytes 5.48kB 0.64%
assets/StudentSelect-*.js 36 bytes 5.46kB 0.66%
assets/ClinicalEffort-*.js -2 bytes 5.33kB -0.04%
assets/ManageEpas-*.js 37 bytes 5.23kB 0.71%
assets/ManageBundles-*.js 37 bytes 5.01kB 0.74%
assets/TermSelection-*.js -2 bytes 4.53kB -0.04%
assets/ManageLevels-*.js 38 bytes 4.52kB 0.85%
assets/FileAuditLog-*.js -1 bytes 4.3kB -0.02%
assets/course-*.js -2 bytes 4.25kB -0.05%
assets/AssessmentEpaEdit-*.js 95 bytes 3.89kB 2.5%
assets/ManageCourseCompetencies-*.js 38 bytes 3.71kB 1.04%
assets/StudentClassYearImport-*.js 37 bytes 3.67kB 1.02%
assets/BiorenderStudents-*.js 38 bytes 3.6kB 1.07%
assets/ClinicalSchedulerHome-*.js 56 bytes 3.57kB 1.59%
assets/ManageMilestones-*.js 37 bytes 3.56kB 1.05%
assets/EffortDialogShell-*.js 35 bytes 3.43kB 1.03%
assets/ContentDiffDialog-*.js -2 bytes 3.39kB -0.06%
assets/cms-*.js -3 bytes 3.37kB -0.09%
assets/StatusIcon-*.js 4 bytes 3.25kB 0.12%
assets/students-*.js 40 bytes 3.23kB 1.25%
assets/ScheduledCliWeeks-*.js -1 bytes 3.07kB -0.03%
assets/AssessmentCompetency-*.js -1 bytes 3.0kB -0.03%
assets/ManageDomains-*.js 38 bytes 2.79kB 1.38%
assets/PercentAssignTypeList-*.js -1 bytes 2.72kB -0.04%
assets/LevelSelect-*.js 39 bytes 2.65kB 1.49%
assets/PercentAssignTypeInstructors-*.js -1 bytes 2.44kB -0.04%
assets/instructor-*.js -2 bytes 2.25kB -0.09%
assets/CtsHome-*.js -112 bytes 2.14kB -4.96%
assets/DateRangeFilter-*.js 1 bytes 2.09kB 0.05%
assets/ManageRoles-*.js 39 bytes 1.95kB 2.04%
assets/emergency-*.js -2 bytes 1.88kB -0.11%
assets/StatusBanner-*.js 1 bytes 1.73kB 0.06%
assets/clinicalscheduler-*.js -3 bytes 1.71kB -0.17%
assets/cahfs-*.js -3 bytes 1.64kB -0.18%
assets/verification-*.js -2 bytes 1.43kB -0.14%
assets/PermissionSelector-*.js 33 bytes 1.37kB 2.47%
assets/RichTextEditor-*.js 1 bytes 1.33kB 0.08%
assets/ModifiedStamp-*.js 1 bytes 1.28kB 0.08%
assets/ReportDeptTabs-*.js -3 bytes 1.12kB -0.27%
assets/computing-*.js -3 bytes 976 bytes -0.31%
assets/unit-*.js -2 bytes 975 bytes -0.2%
assets/main-*.js 101 bytes 848 bytes 13.52% ⚠️
assets/modulepreload-*.js (New) 698 bytes 698 bytes 100.0% 🚀
assets/CAHFSAuth-*.js 34 bytes 666 bytes 5.38% ⚠️
assets/colors-*.js (New) 637 bytes 637 bytes 100.0% 🚀
assets/Home-*.js -2 bytes 564 bytes -0.35%
assets/EditButton-*.js 1 bytes 529 bytes 0.19%
assets/ContentBlock-*.js -2 bytes 526 bytes -0.38%
assets/percent-*.js -2 bytes 501 bytes -0.4%
assets/StatusBadge-*.js 35 bytes 458 bytes 8.27% ⚠️
assets/CheckPagePermission-*.js -2 bytes 150 bytes -1.32%
assets/_plugin-*.js -14.14kB 84 bytes -99.41%

Files in assets/GenericError-*.js:

  • ./src/composables/RequireLogin.ts → Total Size: 2.67kB

Files in assets/CtsHome-*.js:

  • ./src/CTS/pages/CtsHome.vue → Total Size: 124 bytes

@rlorenzo

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor
⚠️ Action not completed

Head commit changed.

@rlorenzo
rlorenzo force-pushed the fix/codeql-sendbackto-redirect branch from f221f78 to 41d48cf Compare August 18, 2026 03:08
@coderabbitai

coderabbitai Bot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@rlorenzo, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 18 minutes

Limit details: You’ve used all 1 included review currently available under your plan.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 49d937f7-8879-4caf-bfda-371d5a931aac

📥 Commits

Reviewing files that changed from the base of the PR and between ee1cfed and 5b681db.

📒 Files selected for processing (3)
  • VueApp/src/CTS/pages/CtsHome.vue
  • VueApp/src/composables/RequireLogin.ts
  • VueApp/src/composables/__tests__/require-login.test.ts
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/codeql-sendbackto-redirect

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.

- replace the always-true fullPath length guard in getLoginUrl, which existed
  only to register a reactive dependency, with a computed that reads the route
  it depends on (CodeQL js/user-controlled-bypass)
- fold requireLogin's duplicate base-prefixing into withApplicationBase
@rlorenzo
rlorenzo force-pushed the fix/codeql-sendbackto-redirect branch from 41d48cf to a172651 Compare August 18, 2026 03:12
@rlorenzo

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor
⚠️ Action not completed

Review rate limited.


Your included review limit is currently reached under our Fair Usage Limits Policy. This review may still proceed through usage-based billing if eligible. Your next included review will be available in 51 minutes.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR addresses two open CodeQL alerts in the Vue SPA authentication/redirect flow by centralizing login URL generation and hardening the sendBackTo deep-link redirect handling.

Changes:

  • Refactors login ReturnUrl creation to derive from route.fullPath and apply a shared application-base prefix (withApplicationBase).
  • Moves CTS post-login sendBackTo redirect logic to the shared handleSendBackToRedirect helper and switches query parsing to Object.fromEntries for prototype-safety.
  • Adds focused unit tests covering rejected redirect targets, query parsing, __proto__ handling, and base-prefix behavior.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
VueApp/src/CTS/pages/CtsHome.vue Uses shared RequireLogin helpers for login redirect and sendBackTo handling.
VueApp/src/composables/RequireLogin.ts Simplifies reactive login URL computation, exports shared helpers, and hardens sendBackTo query parsing.
VueApp/src/composables/tests/require-login.test.ts Adds unit tests validating redirect safety and base-prefixing behavior.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread VueApp/src/composables/RequireLogin.ts
Comment thread VueApp/src/CTS/pages/CtsHome.vue
CtsHome carried its own copy of the post-login redirect and login-URL
build, and the copy skipped the isValidInternalPath guard that the shared
helper applies.

- route CtsHome through handleSendBackToRedirect and buildLoginUrl
- build the redirect query with Object.fromEntries so a "__proto__" key
  stays own data instead of reaching the prototype chain (CodeQL
  js/remote-property-injection)
- keep the current path as the login ReturnUrl so a sendBackTo deep link
  survives the CAS round trip
The guard read useRoute(), the route being navigated away from, so a
pending sendBackTo navigation still saw the query that triggered it and
pushed the same target again, cancelling its own navigation in a loop
(measured 248 cancelled navigations before the URL settled back).

- drop the guard call site so the landing page owns the redirect, which
  CtsHome already does through the shared helper
- document that the helper belongs on the landing page, not in a guard
@rlorenzo
rlorenzo force-pushed the fix/codeql-sendbackto-redirect branch from a172651 to 5b681db Compare August 18, 2026 03:30
@rlorenzo
rlorenzo requested a lite review from Copilot August 18, 2026 03:31
@rlorenzo

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor
⚠️ Action not completed

Review rate limited.

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.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

@rlorenzo

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor
⚠️ Action not completed

Review rate limited.

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants