How can I work around the Django 3.2.10 cve release

74 views
Skip to first unread message

Mike Dewhirst

unread,
May 19, 2022, 11:14:25 PM5/19/22
to Django users
My billing (Stripe) mechanism is working right up until Django 3.2.9 -
which is where I'm stumped at the moment.

Django 3.2.10 https://docs.djangoproject.com/en/3.2/releases/3.2.10/
indicate a URL with a trailing newline can bypass
upstream access control based on URL paths.

Sadly, I am not aware of any such upstream access control.

I have tried to repair it with fixid() within change_view() where
object_id occurs but that doesn't achieve anything.

def fixid(txt):
    try:
        return str(txt).split("/")[0]
    except ValueError:
        pass
    return txt

How can I fix the following error and move forward to 3.2.13?

Many thanks

Mike
- - - - - - - -

Exception Type: ValueError at
/admin/chemical/chemical/29/change/payment/change/
Exception Value: Field 'id' expected a number but got '29/change/payment'.

Environment:

Request Method: GET
Request URL:
http://localhost:8088/admin/chemical/chemical/29/change/payment/change/

Django Version: 3.2.13
Python Version: 3.8.3
Installed Applications:
['filebrowser',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.admin',
 'django.contrib.admindocs',
 'django.contrib.staticfiles',
 'django.contrib.sites',
 'django.contrib.sitemaps',
 'tinymce',
 'billing',
 'chemical',
 'common',
 'company',
 'credit',
 'refer',
 'report']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
 'django.middleware.cache.UpdateCacheMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.locale.LocaleMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.contrib.admindocs.middleware.XViewMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware',
 'pwned_passwords_django.middleware.PwnedPasswordsMiddleware',
 'django.middleware.cache.FetchFromCacheMiddleware']



Traceback (most recent call last):
  File
"D:\Users\mike\envs\xxai\lib\site-packages\django\db\models\fields\__init__.py",
line 1823, in get_prep_value
    return int(value)

The above exception (invalid literal for int() with base 10:
'29/change/payment') was the direct cause of the following exception:
  File
"D:\Users\mike\envs\xxai\lib\site-packages\django\core\handlers\exception.py",
line 47, in inner
    response = get_response(request)
  File
"D:\Users\mike\envs\xxai\lib\site-packages\django\core\handlers\base.py",
line 181, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File
"D:\Users\mike\envs\xxai\lib\site-packages\django\contrib\admin\options.py",
line 616, in wrapper
    return self.admin_site.admin_view(view)(*args, **kwargs)
  File
"D:\Users\mike\envs\xxai\lib\site-packages\django\utils\decorators.py",
line 130, in _wrapped_view
    response = view_func(request, *args, **kwargs)
  File
"D:\Users\mike\envs\xxai\lib\site-packages\django\views\decorators\cache.py",
line 44, in _wrapped_view_func
    response = view_func(request, *args, **kwargs)
  File
"D:\Users\mike\envs\xxai\lib\site-packages\django\contrib\admin\sites.py",
line 232, in inner
    return view(request, *args, **kwargs)
  File "D:\Users\mike\envs\xxai\aicis\chemical\admin.py", line 268, in
change_view
    chemical = Chemical.objects.get(id=object_id)
  File
"D:\Users\mike\envs\xxai\lib\site-packages\django\db\models\manager.py",
line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File
"D:\Users\mike\envs\xxai\lib\site-packages\django\db\models\query.py",
line 424, in get
    clone = self._chain() if self.query.combinator else
self.filter(*args, **kwargs)
  File
"D:\Users\mike\envs\xxai\lib\site-packages\django\db\models\query.py",
line 941, in filter
    return self._filter_or_exclude(False, args, kwargs)
  File
"D:\Users\mike\envs\xxai\lib\site-packages\django\db\models\query.py",
line 961, in _filter_or_exclude
    clone._filter_or_exclude_inplace(negate, args, kwargs)
  File
"D:\Users\mike\envs\xxai\lib\site-packages\django\db\models\query.py",
line 968, in _filter_or_exclude_inplace
    self._query.add_q(Q(*args, **kwargs))
  File
"D:\Users\mike\envs\xxai\lib\site-packages\django\db\models\sql\query.py",
line 1416, in add_q
    clause, _ = self._add_q(q_object, self.used_aliases)
  File
"D:\Users\mike\envs\xxai\lib\site-packages\django\db\models\sql\query.py",
line 1435, in _add_q
    child_clause, needed_inner = self.build_filter(
  File
"D:\Users\mike\envs\xxai\lib\site-packages\django\db\models\sql\query.py",
line 1370, in build_filter
    condition = self.build_lookup(lookups, col, value)
  File
"D:\Users\mike\envs\xxai\lib\site-packages\django\db\models\sql\query.py",
line 1216, in build_lookup
    lookup = lookup_class(lhs, rhs)
  File
"D:\Users\mike\envs\xxai\lib\site-packages\django\db\models\lookups.py",
line 25, in __init__
    self.rhs = self.get_prep_lookup()
  File
"D:\Users\mike\envs\xxai\lib\site-packages\django\db\models\lookups.py",
line 77, in get_prep_lookup
    return self.lhs.output_field.get_prep_value(self.rhs)
  File
"D:\Users\mike\envs\xxai\lib\site-packages\django\db\models\fields\__init__.py",
line 1825, in get_prep_value
    raise e.__class__(

Exception Type: ValueError at
/admin/chemical/chemical/29/change/payment/change/
Exception Value: Field 'id' expected a number but got '29/change/payment'.



--
Signed email is an absolute defence against phishing. This email has
been signed with my private key. If you import my public key you can
automatically decrypt my signature and be sure it came from me. Just
ask and I'll send it to you. Your email software can handle signing.

OpenPGP_signature

Jason

unread,
May 20, 2022, 9:21:09 AM5/20/22
to Django users
are you using re_path for the url in question?

Mike Dewhirst

unread,
May 20, 2022, 9:05:30 PM5/20/22
to django...@googlegroups.com, Jason
On 20/05/2022 11:21 pm, Jason wrote:
are you using re_path for the url in question?

Thanks for responding Jason, yes! Here are my relevant lines ...

    re_path(r"invoice/(?P<pk>\d+)/$", billing_views.invoice_view, name="invoice_view"),
    # no trailing slash or the payment system barfs
    re_path(r"success$", billing_views.success_view, name="success_view"),
    # no trailing slash or the payment system barfs
    re_path(r"payment$", billing_views.payment_view, name="payment_view"),

I'm not particularly keen on re because I have to study the docs to make sense of it every time. If there is an easier way I'll do it!
I looked at the tests and see they are actually looking for '\n' and I'm sure none of my urls end that way.

Cheers

mike

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/8209a97f-3e62-4902-aec7-a4415c5968f6n%40googlegroups.com.
OpenPGP_signature

lavanya gowda

unread,
May 20, 2022, 11:43:30 PM5/20/22
to Django users
Hi mike and jason
 kindly help me to my query also i have shared my query in group  its emergency

my humble request :-

please help me 

here i do have some columns called sub_task_name tht should every day update same perivous task_name but sub_task_value shld not update it shld give option to user to enter new value 

same criteria for task_name  shld  be same perivous  entered but 
user shld get new updation  for this columns

category = models.CharField(max_length=500,blank=True, null=True)
escalation1 = models.IntegerField(blank=True, null=True)
escalation2 = models.IntegerField(blank=True, null=True)
escalation3 = models.IntegerField(blank=True, null=True)
timethershold = models.IntegerField(blank=True, null=True)


my models.py 
class KanbanTask(models.Model):
STATUS_LEVEL = ((1, "Done"), (2, "In Progress"), (3, "On hold"), (4, "Assigned"))

regular_task_id = models.AutoField(primary_key=True)
task_name = models.CharField(max_length=100)
task_department_name = models.CharField(max_length=50, blank=True, null=True)
task_type = models.CharField(max_length=50, blank=True, null=True)
members = JSONField(blank=True, null=True)
task_description = models.CharField(max_length=200, blank=True, null=True)
task_files = models.FileField(upload_to=KanbanRegularTask_doc_directory_path, max_length=200,blank=True, null=True)
task_due_date = models.DateField(blank=True, null=True)
cron = models.CharField(max_length=50, blank=True, null=True)
previous_regular_task_id = models.PositiveIntegerField(blank=True, null=True)
status = models.IntegerField(choices=STATUS_LEVEL, blank=True)
knowledge_center = models.PositiveIntegerField(blank=True, null=True)
created_at = models.DateTimeField(auto_now=True)
updated_at = models.DateTimeField(blank=True, null=True)
category = models.CharField(max_length=500,blank=True, null=True)
escalation1 = models.IntegerField(blank=True, null=True)
escalation2 = models.IntegerField(blank=True, null=True)
escalation3 = models.IntegerField(blank=True, null=True)
timethershold = models.IntegerField(blank=True, null=True)

def __str__(self):
return self.task_name

def KanbanSubTask_doc_directory_path(instance, filename):
return "subtask/%s/%s/%s" %(instance.sub_task_name,instance.sub_task_id, filename)
class KanbanSubTask(models.Model):
sub_tasks = models.ForeignKey(KanbanTask, on_delete=models.CASCADE, related_name='kanbansub_task_regular', null=True, blank=True)
sub_task_id = models.AutoField(primary_key=True)
regular_task_id = models.PositiveIntegerField(blank=True, null=True)
sub_task_name = models.CharField(max_length=200, blank=True, null=True)
sub_task_value = models.CharField(max_length=200, blank=True, null=True)
sub_task_path = models.FileField(upload_to=KanbanSubTask_doc_directory_path, max_length=200,blank=True, null=True)
created_at = models.DateTimeField(auto_now=True)
updated_at = models.DateTimeField(blank=True, null=True)
value_threshold = models.FloatField(blank=True, null=True)

serilzers.py

class KanbanTaskSerializer(serializers.ModelSerializer):
class Meta:
model = KanbanTask
fields = '__all__'

class KanbanSubTaskSerializer(serializers.ModelSerializer):
class Meta:
model = KanbanSubTask
fields = '__all__'

views.py 

class KanbanTaskViewSet(viewsets.ModelViewSet):
pagination_class = None
queryset = KanbanTask.objects.exclude(Q(status=1)&Q(created_at__lte=now_for_filter.strftime('%Y-%m-%d')))
serializer_class = KanbanTaskSerializer

# def update(self, instance, validated_data):
# instance.category = validated_data.get('category', instance.category)
# instance.escalation1 = validated_data.get('escalation1', instance.escalation1)
# instance.escalation2 = validated_data.get('escalation2', instance.escalation2)
# return instance
#
# def create(self, validated_data):
# return Snippet.objects.create(**validated_data)

class KanbanSubTaskViewSet(viewsets.ModelViewSet):
pagination_class = None
queryset = KanbanSubTask.objects.all()
serializer_class = KanbanSubTaskSerializer

def partial_update(self, request, *args, **kwargs):
instance = self.get_object()
data = request.data
try:
kst= KanbanSubTask.objects.get(sub_tasks=data["sub_tasks"])
instance.kst = sub_tasks
except KeyError:
pass
instance.sub_task_id= request.data.sub_task_id("sub_task_id")
instance.sub_task_name = request.data.get("sub_task_name")
instance.sub_task_value = validated_data.get("sub_task_value")
instance.value_threshold = validated_data.get("value_threshold")
instance.save()
serializer = KanbanSubTaskSerializer(instance)
serializer.is_valid(raise_exception=True)
return Response(serializer.data)
# self.perform_update(serializer)
# return Response(serializer.data)


iam hardly trying from few days please guys help me out 

Mike Dewhirst

unread,
May 21, 2022, 1:26:20 AM5/21/22
to django...@googlegroups.com
Lavanya

I'm sorry I don't think I can help with your problem directly but I can help indirectly.

You have "hijacked" this "thread" which means the subject line does not apply to what you are asking.

Only people interested in the actual subject line will look at your message. That cuts out all the people who might be able to help.

Your best approach to getting help is to start a new thread with an interesting subject line summarising what you are looking for.

Good luck with your question

Cheers

Mike



--
(Unsigned mail from my phone)

Lakshyaraj Dash XI-D 25

unread,
May 21, 2022, 4:03:20 AM5/21/22
to django...@googlegroups.com
Hey why don't you use django v4 for your projects? 

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users...@googlegroups.com.

Mike Dewhirst

unread,
May 21, 2022, 5:40:39 AM5/21/22
to django...@googlegroups.com
I'm still on 3.2.x because it is a long term supported version and my project is in production. 

Django 4.0 is really new with asgi replacing wsgi.

I want more unit test coverage before upgrading.

Cheers

Mike

--
(Unsigned mail from my phone)



-------- Original message --------
From: Lakshyaraj Dash XI-D 25 <dashlaksh...@gmail.com>
Date: 21/5/22 18:02 (GMT+10:00)
Subject: Re: How can I work around the Django 3.2.10 cve release

Lakshyaraj Dash XI-D 25

unread,
May 21, 2022, 7:56:55 AM5/21/22
to django...@googlegroups.com
There are not a big bunch of differences. You can also upgrade the version in production. 

Jason

unread,
May 21, 2022, 9:38:51 AM5/21/22
to Django users
https://docs.djangoproject.com/en/4.0/ref/urls/#django.urls.path

This was one of the additions in 2.0, and from what it seems like, you're not doing anything specific with regex that cannot be done with a path alternative.

ie, 

 re_path(r"invoice/(?P<pk>\d+)/$", billing_views.invoice_view, name="invoice_view"),

would be `path("invoice/<int:pk>", billing_views.invoice_view, name="invoice_view")

wonder if this works for you.

also, this might be worth opening a bug ticket about, since this seems like a regression.

Mike Dewhirst

unread,
May 22, 2022, 3:14:34 AM5/22/22
to django...@googlegroups.com
I took your advice but no joy. AND I don't know why!

The "invoice" is in fact the receipt model and receipt.get_absolute_url
just wants the pk value to display what the customer paid.

def get_absolute_url(self):
        """ Show the Invoice receipt """
        return f"/invoice/{self.id}/"

... which matches the re_path for "invoice_view" below as well as the
model view in the Admin.

Looking at the Invoice/Receipt in the Admin the url is ...

     http://localhost:8088/admin/billing/receipt/67/change/

HOWEVER when rolling the mouse across the (View on site) button in the
Admin, I see a strange URL which actually works!

     http://localhost:8088/admin/r/49/67/            # no idea what the
r/49 is

... and when (View on site) is clicked the resulting Invoice/Receipt
appears exactly as expected with url ...

     http://localhost:8088/invoice/67/

So if I take your advice and use ...

>
> would be `path("invoice/<int:pk>", billing_views.invoice_view,
> name="invoice_view")
>
... 'View on site' barfs with ...


Page not found (404)

Request Method: GET
Request URL: http://localhost:8088/invoice/67/

Using the URLconf defined in |xxx.urls|, Django tried these URL
patterns, in this order:

1. ^admin/filebrowser/
2. ^tinymce/
3. ^500/$
4. ^401/$
5. ^403/$
6. ^404/$
7. ^admin/500/$
8. ^admin/401/$
9. ^admin/403/$
10. ^admin/404/$
11. invoice/<int:pk> [name='invoice_view']
12. success$ [name='success_view']
13. payment$ [name='payment_view']
<snip>

All this by the way is with Django 3.2.9. Version 3.2.10 to 3.2.13 all
fail as per my original request for advice to which you suggested I file
a bug.

I'm somewhat baffled.

As for filing a bug I'm not sure what to say.

For the moment I'm stuck with re_path and version 3.2.9 in production.

Thanks again for listening and if you think I should post more code I'm
happy to do that.

Cheers

Mike



On 21/05/2022 11:38 pm, Jason wrote:
> https://docs.djangoproject.com/en/4.0/ref/urls/#django.urls.path
>
> This was one of the additions in 2.0, and from what it seems like,
> you're not doing anything specific with regex that cannot be done with
> a path alternative.
>
> ie,
>
>  re_path(r"invoice/(?P<pk>\d+)/$", billing_views.invoice_view,
> name="invoice_view"),
>
> would be `path("invoice/<int:pk>", billing_views.invoice_view,
> name="invoice_view")
>
> wonder if this works for you.
>
> also, this might be worth opening a bug ticket about, since this seems
> like a regression.
>
>
>> <https://groups.google.com/d/msgid/django-users/8209a97f-3e62-4902-aec7-a4415c5968f6n%40googlegroups.com?utm_medium=email&utm_source=footer>.
>
>
> --
> Signed email is an absolute defence against phishing. This email has
> been signed with my private key. If you import my public key you can
> automatically decrypt my signature and be sure it came from me. Just
> ask and I'll send it to you. Your email software can handle signing.
> --
> You received this message because you are subscribed to the Google
> Groups "Django users" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to django-users...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/django-users/14cb3e24-f158-e689-2354-b2adaea07a8c%40dewhirst.com.au
> <https://groups.google.com/d/msgid/django-users/14cb3e24-f158-e689-2354-b2adaea07a8c%40dewhirst.com.au?utm_medium=email&utm_source=footer>.
OpenPGP_signature
Reply all
Reply to author
Forward
0 new messages