VYPR
High severityNVD Advisory· Published Jan 10, 2011· Updated Apr 29, 2026

CVE-2010-4534

CVE-2010-4534

Description

The administrative interface in django.contrib.admin in Django before 1.1.3, 1.2.x before 1.2.4, and 1.3.x before 1.3 beta 1 does not properly restrict use of the query string to perform certain object filtering, which allows remote authenticated users to obtain sensitive information via a series of requests containing regular expressions, as demonstrated by a created_by__password__regex parameter.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
DjangoPyPI
< 1.1.31.1.3
DjangoPyPI
>= 1.2, < 1.2.41.2.4

Affected products

16
  • cpe:2.3:a:djangoproject:django:*:*:*:*:*:*:*:*+ 15 more
    • cpe:2.3:a:djangoproject:django:*:*:*:*:*:*:*:*range: <=1.1.2
    • cpe:2.3:a:djangoproject:django:0.91:*:*:*:*:*:*:*
    • cpe:2.3:a:djangoproject:django:0.95:*:*:*:*:*:*:*
    • cpe:2.3:a:djangoproject:django:0.95.1:*:*:*:*:*:*:*
    • cpe:2.3:a:djangoproject:django:0.96:*:*:*:*:*:*:*
    • cpe:2.3:a:djangoproject:django:1.0:*:*:*:*:*:*:*
    • cpe:2.3:a:djangoproject:django:1.0.1:*:*:*:*:*:*:*
    • cpe:2.3:a:djangoproject:django:1.0.2:*:*:*:*:*:*:*
    • cpe:2.3:a:djangoproject:django:1.1:*:*:*:*:*:*:*
    • cpe:2.3:a:djangoproject:django:1.1.0:*:*:*:*:*:*:*
    • cpe:2.3:a:djangoproject:django:1.2:*:*:*:*:*:*:*
    • cpe:2.3:a:djangoproject:django:1.2.1:*:*:*:*:*:*:*
    • cpe:2.3:a:djangoproject:django:1.2.2:*:*:*:*:*:*:*
    • cpe:2.3:a:djangoproject:django:1.2.3:*:*:*:*:*:*:*
    • cpe:2.3:a:djangoproject:django:1.3:alpha1:*:*:*:*:*:*
    • cpe:2.3:a:djangoproject:django:1.3:alpha2:*:*:*:*:*:*

Patches

2
17084839fd7e

[1.1.X] Fix a security issue in the admin. Disclosure and new release forthcoming.

https://github.com/django/djangoAlex GaynorDec 23, 2010via ghsa
4 files changed · +49 4
  • django/contrib/admin/options.py+27 1 modified
    @@ -8,7 +8,9 @@
     from django.contrib.admin.util import unquote, flatten_fieldsets, get_deleted_objects, model_ngettext, model_format_dict
     from django.core.exceptions import PermissionDenied, ValidationError
     from django.db import models, transaction
    -from django.db.models.fields import BLANK_CHOICE_DASH
    +from django.db.models.related import RelatedObject
    +from django.db.models.fields import BLANK_CHOICE_DASH, FieldDoesNotExist
    +from django.db.models.sql.constants import LOOKUP_SEP, QUERY_TERMS
     from django.http import Http404, HttpResponse, HttpResponseRedirect
     from django.shortcuts import get_object_or_404, render_to_response
     from django.utils.datastructures import SortedDict
    @@ -171,6 +173,30 @@ def _declared_fieldsets(self):
             return None
         declared_fieldsets = property(_declared_fieldsets)
     
    +    def lookup_allowed(self, lookup):
    +        parts = lookup.split(LOOKUP_SEP)
    +
    +        # Last term in lookup is a query term (__exact, __startswith etc)
    +        # This term can be ignored.
    +        if len(parts) > 1 and parts[-1] in QUERY_TERMS:
    +            parts.pop()
    +
    +        # Special case -- foo__id__exact and foo__id queries are implied
    +        # if foo has been specificially included in the lookup list; so
    +        # drop __id if it is the last part.
    +        if len(parts) > 1 and parts[-1] == self.model._meta.pk.name:
    +            parts.pop()
    +
    +        try:
    +            self.model._meta.get_field_by_name(parts[0])
    +        except FieldDoesNotExist:
    +            # Lookups on non-existants fields are ok, since they're ignored
    +            # later.
    +            return True
    +        else:
    +            clean_lookup = LOOKUP_SEP.join(parts)
    +            return clean_lookup in self.list_filter or clean_lookup == self.date_hierarchy
    +
     class ModelAdmin(BaseModelAdmin):
         "Encapsulates all admin options and functionality for a given model."
     
    
  • django/contrib/admin/views/main.py+7 1 modified
    @@ -1,6 +1,7 @@
     from django.contrib.admin.filterspecs import FilterSpec
     from django.contrib.admin.options import IncorrectLookupParameters
     from django.contrib.admin.util import quote
    +from django.core.exceptions import SuspiciousOperation
     from django.core.paginator import Paginator, InvalidPage
     from django.db import models
     from django.db.models.query import QuerySet
    @@ -192,13 +193,18 @@ def get_query_set(self):
                     else:
                         lookup_params[key] = True
     
    +            if not self.model_admin.lookup_allowed(key):
    +                raise SuspiciousOperation(
    +                    "Filtering by %s not allowed" % key
    +                )
    +
             # Apply lookup parameters from the query string.
             try:
                 qs = qs.filter(**lookup_params)
             # Naked except! Because we don't have any other way of validating "params".
             # They might be invalid if the keyword arguments are incorrect, or if the
             # values are not in the correct type, so we might get FieldError, ValueError,
    -        # ValicationError, or ? from a custom field that raises yet something else 
    +        # ValicationError, or ? from a custom field that raises yet something else
             # when handed impossible data.
             except:
                 raise IncorrectLookupParameters
    
  • tests/regressiontests/admin_views/models.py+10 2 modified
    @@ -7,7 +7,7 @@
     from django.core.mail import EmailMessage
     from django import forms
     from django.forms.models import BaseModelFormSet
    -
    +from django.contrib.auth.models import User
     from django.contrib.contenttypes import generic
     from django.contrib.contenttypes.models import ContentType
     
    @@ -89,7 +89,7 @@ class ChapterInline(admin.TabularInline):
     
     class ArticleAdmin(admin.ModelAdmin):
         list_display = ('content', 'date', callable_year, 'model_year', 'modeladmin_year')
    -    list_filter = ('date',)
    +    list_filter = ('date', 'section')
     
         def changelist_view(self, request):
             "Test that extra_context works"
    @@ -505,6 +505,13 @@ class CyclicTwo(models.Model):
         def __unicode__(self):
             return self.name
     
    +class Album(models.Model):
    +    owner = models.ForeignKey(User)
    +    title = models.CharField(max_length=30)
    +
    +class AlbumAdmin(admin.ModelAdmin):
    +    list_filter = ['title']
    +
     admin.site.register(Article, ArticleAdmin)
     admin.site.register(CustomArticle, CustomArticleAdmin)
     admin.site.register(Section, save_as=True, inlines=[ArticleInline])
    @@ -547,3 +554,4 @@ def __unicode__(self):
     admin.site.register(Book, inlines=[ChapterInline])
     admin.site.register(Promo)
     admin.site.register(ChapterXtra1)
    +admin.site.register(Album, AlbumAdmin)
    \ No newline at end of file
    
  • tests/regressiontests/admin_views/tests.py+5 0 modified
    @@ -3,6 +3,7 @@
     import re
     import datetime
     from django.conf import settings
    +from django.core.exceptions import SuspiciousOperation
     from django.core.files import temp as tempfile
     from django.contrib.auth.models import User, Permission
     from django.contrib.contenttypes.models import ContentType
    @@ -289,6 +290,10 @@ def testI18NLanguageNonEnglishFallback(self):
             self.assertContains(response, 'Choisir une heure')
             deactivate()
     
    +    def test_disallowed_filtering(self):
    +        self.assertRaises(SuspiciousOperation,
    +            self.client.get, "/test_admin/admin/admin_views/album/?owner__email__startswith=fuzzy"
    +        )
     
     class SaveAsTests(TestCase):
         fixtures = ['admin-views-users.xml','admin-views-person.xml']
    
85207a245bf0

Fix a security issue in the admin. Disclosure and new release forthcoming.

https://github.com/django/djangoAlex GaynorDec 23, 2010via ghsa
4 files changed · +44 4
  • django/contrib/admin/options.py+27 1 modified
    @@ -10,7 +10,9 @@
     from django.views.decorators.csrf import csrf_protect
     from django.core.exceptions import PermissionDenied, ValidationError
     from django.db import models, transaction
    -from django.db.models.fields import BLANK_CHOICE_DASH
    +from django.db.models.related import RelatedObject
    +from django.db.models.fields import BLANK_CHOICE_DASH, FieldDoesNotExist
    +from django.db.models.sql.constants import LOOKUP_SEP, QUERY_TERMS
     from django.http import Http404, HttpResponse, HttpResponseRedirect
     from django.shortcuts import get_object_or_404, render_to_response
     from django.utils.decorators import method_decorator
    @@ -183,6 +185,30 @@ def _declared_fieldsets(self):
         def get_readonly_fields(self, request, obj=None):
             return self.readonly_fields
     
    +    def lookup_allowed(self, lookup):
    +        parts = lookup.split(LOOKUP_SEP)
    +
    +        # Last term in lookup is a query term (__exact, __startswith etc)
    +        # This term can be ignored.
    +        if len(parts) > 1 and parts[-1] in QUERY_TERMS:
    +            parts.pop()
    +
    +        # Special case -- foo__id__exact and foo__id queries are implied
    +        # if foo has been specificially included in the lookup list; so
    +        # drop __id if it is the last part.
    +        if len(parts) > 1 and parts[-1] == self.model._meta.pk.name:
    +            parts.pop()
    +
    +        try:
    +            self.model._meta.get_field_by_name(parts[0])
    +        except FieldDoesNotExist:
    +            # Lookups on non-existants fields are ok, since they're ignored
    +            # later.
    +            return True
    +        else:
    +            clean_lookup = LOOKUP_SEP.join(parts)
    +            return clean_lookup in self.list_filter or clean_lookup == self.date_hierarchy
    +
     class ModelAdmin(BaseModelAdmin):
         "Encapsulates all admin options and functionality for a given model."
     
    
  • django/contrib/admin/views/main.py+7 1 modified
    @@ -1,6 +1,7 @@
     from django.contrib.admin.filterspecs import FilterSpec
     from django.contrib.admin.options import IncorrectLookupParameters
     from django.contrib.admin.util import quote
    +from django.core.exceptions import SuspiciousOperation
     from django.core.paginator import Paginator, InvalidPage
     from django.db import models
     from django.db.models.query import QuerySet
    @@ -187,13 +188,18 @@ def get_query_set(self):
                     else:
                         lookup_params[key] = True
     
    +            if not self.model_admin.lookup_allowed(key):
    +                raise SuspiciousOperation(
    +                    "Filtering by %s not allowed" % key
    +                )
    +
             # Apply lookup parameters from the query string.
             try:
                 qs = qs.filter(**lookup_params)
             # Naked except! Because we don't have any other way of validating "params".
             # They might be invalid if the keyword arguments are incorrect, or if the
             # values are not in the correct type, so we might get FieldError, ValueError,
    -        # ValicationError, or ? from a custom field that raises yet something else 
    +        # ValicationError, or ? from a custom field that raises yet something else
             # when handed impossible data.
             except:
                 raise IncorrectLookupParameters
    
  • tests/regressiontests/admin_views/models.py+5 2 modified
    @@ -92,7 +92,7 @@ class ChapterInline(admin.TabularInline):
     
     class ArticleAdmin(admin.ModelAdmin):
         list_display = ('content', 'date', callable_year, 'model_year', 'modeladmin_year')
    -    list_filter = ('date',)
    +    list_filter = ('date', 'section')
     
         def changelist_view(self, request):
             "Test that extra_context works"
    @@ -584,6 +584,9 @@ class Album(models.Model):
         owner = models.ForeignKey(User)
         title = models.CharField(max_length=30)
     
    +class AlbumAdmin(admin.ModelAdmin):
    +    list_filter = ['title']
    +
     admin.site.register(Article, ArticleAdmin)
     admin.site.register(CustomArticle, CustomArticleAdmin)
     admin.site.register(Section, save_as=True, inlines=[ArticleInline])
    @@ -630,4 +633,4 @@ class Album(models.Model):
     admin.site.register(ChapterXtra1)
     admin.site.register(Pizza, PizzaAdmin)
     admin.site.register(Topping)
    -admin.site.register(Album)
    +admin.site.register(Album, AlbumAdmin)
    
  • tests/regressiontests/admin_views/tests.py+5 0 modified
    @@ -4,6 +4,7 @@
     import datetime
     
     from django.conf import settings
    +from django.core.exceptions import SuspiciousOperation
     from django.core.files import temp as tempfile
     # Register auth models with the admin.
     from django.contrib.auth import REDIRECT_FIELD_NAME, admin
    @@ -300,6 +301,10 @@ def testI18NLanguageNonEnglishFallback(self):
             self.assertContains(response, 'Choisir une heure')
             deactivate()
     
    +    def test_disallowed_filtering(self):
    +        self.assertRaises(SuspiciousOperation,
    +            self.client.get, "/test_admin/admin/admin_views/album/?owner__email__startswith=fuzzy"
    +        )
     
     class SaveAsTests(TestCase):
         fixtures = ['admin-views-users.xml','admin-views-person.xml']
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

26

News mentions

0

No linked articles in our index yet.