Security releases issued

Posted by James Bennett on April 21, 2014

Today the Django team is issuing multiple releases -- Django 1.4.11, Django 1.5.6, Django 1.6.3 and Django 1.7 beta 2 -- as part of our security process. These releases are now available on PyPI and our download page.

These releases address an unexpected code-execution issue, a caching issue which can expose CSRF tokens and a MySQL typecasting issue. While these issues present limited risk and may not affect all Django users, we encourage all users to evaluate their own risk and upgrade as soon as possible.

For more details, read on.

Issue: Unexpected code execution using reverse()

Django's URL handling is based on a mapping of regex patterns (representing the URLs) to callable views, and Django's own processing consists of matching a requested URL against those patterns to determine the appropriate view to invoke.

Django also provides a convenience function -- django.core.urlresolvers.reverse() -- which performs this process in the opposite direction. The reverse() function takes information about a view and returns a URL which would invoke that view. Use of reverse() is encouraged for application developers, as the output of reverse() is always based on the current URL patterns, meaning developers do not need to change other code when making changes to URLs.

One argument signature for reverse() is to pass a dotted Python path to the desired view. In this situation, Django will import the module indicated by that dotted path as part of generating the resulting URL. If such a module has import-time side effects, those side effects will occur.

Thus it is possible for an attacker to cause unexpected code execution, given the following conditions:

  1. One or more views are present which construct a URL based on user input (commonly, a "next" parameter in a querystring indicating where to redirect upon successful completion of an action).
  2. One or more modules are known to an attacker to exist on the server's Python import path, which perform code execution with side effects on importing.

To remedy this, reverse() will now only accept and import dotted paths based on the view-containing modules listed in the project's URL pattern configuration, so as to ensure that only modules the developer intended to be imported in this fashion can or will be imported.

This issue has been assigned the CVE identifier CVE-2014-0472.

Thanks to Benjamin Bach for reporting this issue.

Issue: Caching of anonymous pages could reveal CSRF token

Django includes both a caching framework and a system for preventing cross-site request forgery (CSRF) attacks. The CSRF-protection system is based on a random nonce sent to the client in a cookie which must be sent by the client on future requests and, in forms, a hidden value which must be submitted back with the form.

The caching framework includes an option to cache responses to anonymous (i.e., unauthenticated) clients.

When the first anonymous request to a given page is by a client which did not have a CSRF cookie, the cache framework will also cache the CSRF cookie and serve the same nonce to other anonymous clients who do not have a CSRF cookie. This can allow an attacker to obtain a valid CSRF cookie value and perform attacks which bypass the check for the cookie.

To remedy this, the caching framework will no longer cache such responses. The heuristic for this will be:

  1. If the incoming request did not submit any cookies, and
  2. If the response did send one or more cookies, and
  3. If the Vary: Cookie header is set on the response, then the response will not be cached.

This issue has been assigned the CVE identifier CVE-2014-0473.

Thanks to committer Paul McMillan for reporting this issue.

Issue: MySQL typecasting

The MySQL database is known to "typecast" on certain queries; for example, when querying a table which contains string values, but using a query which filters based on an integer value, MySQL will first silently coerce the strings to integers, and return a result based on that.

If a query is performed without first converting values to the appropriate type, this can produce unexpected results, similar to what would occur if the query itself had been manipulated.

Django's model field classes are aware of their own types and most such classes perform explicit conversion of query arguments to the correct database-level type before querying. However, three model field classes did not correctly convert their arguments:

  • FilePathField
  • GenericIPAddressField
  • IPAddressField

These three fields have been updated to convert their arguments to the correct types before querying.

Additionally, developers of custom model fields are now warned via documentation to ensure their custom field classes will perform appropriate type conversions, and users of the raw() and extra() query methods -- which allow the developer to supply raw SQL or SQL fragments -- will be advised to ensure they perform appropriate manual type conversions prior to executing queries.

This issue has been assigned the CVE identifier CVE-2014-0474.

Thanks to the Ruby on Rails team, and specifically Michael Koziarski, for providing information regarding this issue.

Affected versions

  • Django master development branch
  • Django 1.7 (currently at beta status)
  • Django 1.6
  • Django 1.5
  • Django 1.4


Patches have been applied to Django's master development branch, and to the 1.4, 1.5, 1.6 and 1.7 release branches, which resolve the issues described above. The patches may be obtained directly from the following changesets:

On the development master branch:

On the Django 1.7 release branch:

On the Django 1.6 release branch:

On the Django 1.5 release branch:

On the Django 1.4 release branch:

The following new releases have been issued:

General notes regarding security reporting

As always, we ask that potential security issues be reported via private email to, and not via Django's Trac instance or the django-developers list. Please see our security policies for further information.

UPDATE: 1850 CST 21 Apr 2014 - The version numbers at the end of this post mistakenly referenced version 1.5.7, instead of 1.5.6.

Back to Top