From 84d9b4704a715dc64d3697e63fcec6ed268f3889 Mon Sep 17 00:00:00 2001 From: Keith Smith Date: Tue, 23 Dec 2025 06:25:22 -0700 Subject: [PATCH] Fix MEDIUM-HIGH Security Issue: Add input validation for choice fields MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added validation for status, priority, and recurrence fields in web forms to prevent invalid database values. Changes: TaskUpdateView.post() (line 419): - Validate status against Task.STATUS_CHOICES before setting - Validate priority against Task.PRIORITY_CHOICES before setting - Validate recurrence against Task.RECURRENCE_CHOICES before setting - Only update fields if value is in allowed choices - Default to 'none' for invalid recurrence values TaskCreateView.post() (line 481): - Validate status, default to 'pending' if invalid - Validate priority, default to 'medium' if invalid - Validate recurrence, default to 'none' if invalid - Prevents creation with invalid choice values Allowed Choices: - Status: pending, in_progress, completed, cancelled - Priority: low, medium, high, urgent - Recurrence: none, daily, weekly, biweekly, monthly Security impact: - Prevents invalid database values from user input - Maintains data integrity - Blocks potential business logic bypasses - Prevents database constraint violations 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- tasks/views.py | 46 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/tasks/views.py b/tasks/views.py index 8c86c02..1596118 100644 --- a/tasks/views.py +++ b/tasks/views.py @@ -424,8 +424,18 @@ class TaskDetailView(View): task.title = request.POST.get('title', task.title) task.description = request.POST.get('description', '') - task.status = request.POST.get('status', task.status) - task.priority = request.POST.get('priority', task.priority) + + # Validate status against allowed choices + status = request.POST.get('status', task.status) + valid_statuses = [choice[0] for choice in Task.STATUS_CHOICES] + if status in valid_statuses: + task.status = status + + # Validate priority against allowed choices + priority = request.POST.get('priority', task.priority) + valid_priorities = [choice[0] for choice in Task.PRIORITY_CHOICES] + if priority in valid_priorities: + task.priority = priority due_date = request.POST.get('due_date') task.due_date = due_date if due_date else None @@ -433,7 +443,13 @@ class TaskDetailView(View): due_time = request.POST.get('due_time') task.due_time = due_time if due_time else None - task.recurrence = request.POST.get('recurrence', 'none') + # Validate recurrence against allowed choices + recurrence = request.POST.get('recurrence', 'none') + valid_recurrences = [choice[0] for choice in Task.RECURRENCE_CHOICES] + if recurrence in valid_recurrences: + task.recurrence = recurrence + else: + task.recurrence = 'none' task.save() @@ -466,15 +482,33 @@ class TaskCreateView(View): if not request.user.is_authenticated: return redirect('login') + # Validate status against allowed choices + status = request.POST.get('status', 'pending') + valid_statuses = [choice[0] for choice in Task.STATUS_CHOICES] + if status not in valid_statuses: + status = 'pending' + + # Validate priority against allowed choices + priority = request.POST.get('priority', 'medium') + valid_priorities = [choice[0] for choice in Task.PRIORITY_CHOICES] + if priority not in valid_priorities: + priority = 'medium' + + # Validate recurrence against allowed choices + recurrence = request.POST.get('recurrence', 'none') + valid_recurrences = [choice[0] for choice in Task.RECURRENCE_CHOICES] + if recurrence not in valid_recurrences: + recurrence = 'none' + task = Task.objects.create( user=request.user, title=request.POST.get('title'), description=request.POST.get('description', ''), - status=request.POST.get('status', 'pending'), - priority=request.POST.get('priority', 'medium'), + status=status, + priority=priority, due_date=request.POST.get('due_date') or None, due_time=request.POST.get('due_time') or None, - recurrence=request.POST.get('recurrence', 'none'), + recurrence=recurrence, ) tag_ids = request.POST.getlist('tags')