Summary
A security audit identified 12 authorization vulnerabilities (2 Critical, 6 High, 4 Medium) in free-pmo.
Critical Findings
1. Unauthenticated Issue Option Update (CRITICAL)
routes/web/projects.php:110-120 — Issue option update and comment routes are defined outside both Route::group(['middleware' => ['auth']]) blocks:
Route::patch('issues/{issue}/options', 'Issues\OptionController@update');
Route::post('issues/{issue}/comments', 'Issues\CommentController@store');
Route::patch('issues/{issue}/comments/{comment}', 'Issues\CommentController@update');
Route::delete('issues/{issue}/comments/{comment}', 'Issues\CommentController@destroy');
The OptionController@update has NO $this->authorize() call — an unauthenticated user can change any issue's priority, status, and assigned person via PATCH /issues/{id}/options.
2. manage_jobs Gate Always Returns True (CRITICAL)
AuthServiceProvider.php:44-46:
Gate::define('manage_jobs', function ($user, $project) {
return true;
});
This gate is used by Jobs\CreateRequest, UpdateRequest, and DeleteRequest. Any authenticated worker can create, update (including prices), and delete jobs on ANY project, regardless of project membership.
HIGH Findings — Missing Authorization in Controllers
The ProjectsController has thorough $this->authorize() calls, but sibling controllers in the same namespace have ZERO authorization:
- IssueController — full CRUD on any project's issues without auth
- Projects/JobsController — list, export (including pricing data), and copy jobs between any projects
- ActivityController — view any project's activity history
- FilesController — upload/download/edit/delete files for any project
- TasksController
setDone/setAsJob — mark any task complete or convert to job
- API ProjectsController — IDOR: retrieve any project's full details by ID
MEDIUM Findings
- JobsController@edit uses
view policy instead of update
- JobsController@delete confirmation page — no auth
- LogFileController — path traversal in
$fileName parameter (admin-only)
- BackupsController — path traversal in download/delete/restore (admin-only)
Recommended Fixes
- Move issue option/comment routes inside the auth middleware group
- Implement proper
manage_jobs gate with project membership check:
Gate::define('manage_jobs', function ($user, $project) {
return $user->hasRole('admin') || $project->owner_id == $user->id;
});
- Add
$this->authorize() calls to all Project-related controllers
- Sanitize
$fileName in LogFileController and BackupsController
Disclosure
Filed in good faith. No exploit code provided.
Summary
A security audit identified 12 authorization vulnerabilities (2 Critical, 6 High, 4 Medium) in free-pmo.
Critical Findings
1. Unauthenticated Issue Option Update (CRITICAL)
routes/web/projects.php:110-120— Issue option update and comment routes are defined outside bothRoute::group(['middleware' => ['auth']])blocks:The
OptionController@updatehas NO$this->authorize()call — an unauthenticated user can change any issue's priority, status, and assigned person viaPATCH /issues/{id}/options.2. manage_jobs Gate Always Returns True (CRITICAL)
AuthServiceProvider.php:44-46:This gate is used by
Jobs\CreateRequest,UpdateRequest, andDeleteRequest. Any authenticated worker can create, update (including prices), and delete jobs on ANY project, regardless of project membership.HIGH Findings — Missing Authorization in Controllers
The
ProjectsControllerhas thorough$this->authorize()calls, but sibling controllers in the same namespace have ZERO authorization:setDone/setAsJob— mark any task complete or convert to jobMEDIUM Findings
viewpolicy instead ofupdate$fileNameparameter (admin-only)Recommended Fixes
manage_jobsgate with project membership check:$this->authorize()calls to all Project-related controllers$fileNamein LogFileController and BackupsControllerDisclosure
Filed in good faith. No exploit code provided.