Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions checkers/python/post-after-isvalid.test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
from django.shortcuts import render, redirect
from .models import *
from .forms import *


# The idea here is to create an model object called a Tournament, with a form for creation called CreateTournamentForm()
#
# Django best practices are to use form.cleaned_data[] after validation to ensure you're accessing well-sanitized data:
# https://docs.djangoproject.com/en/4.2/ref/forms/api/#accessing-clean-data
#
# Some fairly typical django form object creation handlers
# This handler does NOT use request.cleaned_data[], even after form.is_valid() has run
def create_new_tournament_dangerous(request):
if request.method == 'POST':
form = CreateTournamentForm(request.POST)
if form.is_valid():
# <expect-error>
t = Tournament(name=request.POST['name'])
t.save()
return redirect('index')
else:
context = { 'form': CreateTournamentForm()}
return render(request, 'create_tournament.html', context)

def create_new_tournament_dangerous(request):
if request.method == 'POST':
form = CreateTournamentForm(request.POST)
if form.is_valid():
# <expect-error>
t = Tournament(name=request.POST.get('name'))
t.save()
return redirect('index')
else:
context = { 'form': CreateTournamentForm()}
return render(request, 'create_tournament.html', context)

# This handler DOES use request.cleaned_data[], even after form.is_valid() has run
def create_new_tournament_safe(request):
if request.method == 'POST':
form = CreateTournamentForm(request.POST)
if form.is_valid():
# <no-error>
t = Tournament(name=form.cleaned_data['name'])
t.save()
return redirect('index')
else:
context = { 'form': CreateTournamentForm()}
return render(request, 'create_tournament.html', context)
36 changes: 36 additions & 0 deletions checkers/python/post-after-isvalid.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
language: py
name: post-after-isvalid
message: After form.is_valid(), use form.cleaned_data[] instead of request.POST[] or request.POST.get() to ensure data is sanitized.
category: security

pattern: |
(subscript
value: (attribute
object: (identifier) @request
attribute: (identifier) @post)
subscript: (_)
(#eq? @request "request")
(#eq? @post "POST")) @post-after-isvalid

(call
function: (attribute
object: (attribute
object: (identifier) @request
attribute: (identifier) @post)
attribute: (identifier) @get)
(#eq? @request "request")
(#eq? @post "POST")
(#eq? @get "get")) @post-after-isvalid

filters:
- pattern-inside: |
(if_statement
condition: (call
function: (attribute
object: (identifier)
attribute: (identifier) @isvalid)
arguments: (argument_list))
(#eq? @isvalid "is_valid"))

description: |
Use form.cleaned_data[] instead of request.POST[]/request.POST.get() after form.is_valid() to access only sanitized data