app: validate resolved path in open-plugin-folder before opening it#6473
Conversation
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: krsatyamthakur-droid The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
There was a problem hiding this comment.
Pull request overview
This PR hardens the Electron desktop app’s open-plugin-folder IPC handler against path traversal by ensuring the renderer-supplied folderName cannot resolve outside the expected plugins base directory before calling shell.openPath.
Changes:
- Added
isPathWithinDirectory()helper to validate a target path stays within a base directory. - Updated the
open-plugin-folderIPC handler to reject resolved paths that escape the expected plugins directory and log the attempt. - Added unit tests covering allowed and rejected path cases for
isPathWithinDirectory().
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| app/electron/plugin-management.ts | Adds isPathWithinDirectory() helper used for validating renderer-influenced paths. |
| app/electron/main.ts | Applies the helper in the open-plugin-folder IPC handler before invoking shell.openPath. |
| app/electron/plugin-management.test.ts | Adds test coverage for the new path-within-directory helper. |
illume
left a comment
There was a problem hiding this comment.
Thanks for these changes.
Can you please address the open review comments? Once you've resolved each one, please mark it as resolved.
|
@illume all three fixed, ptal |
The open-plugin-folder IPC handler joined the renderer-supplied folderName onto the plugins base directory and passed the result straight to shell.openPath, with no check that it stayed inside that directory. A folderName like "../../../../etc" resolves outside the plugins folder, and shell.openPath opens (or, for a file, launches) whatever it lands on, so a crafted name could open something well outside the plugins directory. Add isPathWithinDirectory() in plugin-management.ts and use it to reject any resolved path that escapes the base directory before calling shell.openPath. Since the IPC payload is untrusted, also guard against a null or non-string folderName, and check the string that shell.openPath resolves with (it resolves with an error message rather than rejecting) so failures are logged. Add tests for isPathWithinDirectory covering a normal folder, a nested subdirectory, a name that starts with "..", a traversal attempt, the base directory itself, and an unrelated absolute path. Signed-off-by: satyam kumar <krsatyamthakur@gmail.com>
bc0d3b8 to
b4c82da
Compare
Summary
The open-plugin-folder IPC handler joined the renderer-supplied folderName onto the plugins base directory and passed the result straight to shell.openPath, with no check that the joined path actually stayed inside that directory. A folderName like "../../../../etc" resolves outside the plugins folder entirely, and shell.openPath doesn't just browse directories - given a file path it opens that file with the OS's default handler, so this could end up launching something rather than just showing the wrong folder.
Added isPathWithinDirectory() in plugin-management.ts and used it to reject any resolved path that escapes the expected base directory before calling shell.openPath, logging the attempt instead.
Related Issue
Fixes #6472
Changes
Steps to Test
Screenshots (if applicable)
N/A, this is a main-process validation change with nothing visual to show.
Notes for the Reviewer
I pulled the check out into plugin-management.ts instead of leaving it inline in main.ts since that file already has test coverage, and nothing else in the codebase imports main.ts directly in a test (would mean mocking electron, yargs, dotenv, etc for basically no benefit).