Opened 98 minutes ago
#36945 assigned Bug
.values() and .order_by() miss FilteredRelation when resolving aliases shadowing relationship traversals
| Reported by: | Jacob Walls | Owned by: | Sarah Boyce |
|---|---|---|---|
| Component: | Database layer (models, ORM) | Version: | 6.0 |
| Severity: | Normal | Keywords: | FilteredRelation, alias |
| Cc: | Triage Stage: | Unreviewed | |
| Has patch: | no | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
Here is a fiddle on DryORM demonstrating that when .values()/.values_list() resolve aliases, they appropriately give priority to most aliases supplied by .annotate()/.alias() before trying to parse __ as relationship traversals, but fail to account for annotations consisting of FilteredRelation, which are stored in a different internal data structure and therefore missed.
This leads to resolving an alias that happens to contain __ as a relationship traversal instead of the alias that was requested.
Here is the reproducer:
from django.db import models from django.contrib.auth.models import User from django.contrib.contenttypes.models import ContentType class Person(models.Model): name = models.CharField(max_length=100) creator = models.ForeignKey(User, models.CASCADE, null=True) ct = models.ForeignKey(ContentType, models.CASCADE) def run(): admin = User.objects.create(username='admin') person_ct = ContentType.objects.get_for_model(Person) Person.objects.create(creator=admin, name="Prince", ct=person_ct) alias = "ct__model" # This does not resolve to ContentType.model. Returns Person.creator_id qs = Person.objects.annotate(**{alias: models.F("creator")}).values(alias) print(qs) # This does resolve to ContentType.model. Returns Person.ct.model qs = Person.objects.annotate( **{alias: models.FilteredRelation("creator", condition=models.Q(creator__isnull=False))} ).values(alias) print(qs)
Output:
<QuerySet [{'ct__model': 1}]>
<QuerySet [{'ct__model': 'person'}]>
In this example, since alias is a variable, and could be user-controlled in the case of user-configurable reports, it is unexpected that for some values of alias, the column it maps to might vary.
.order_by() is affected in the same way.
While this is not regarded as a security vulnerability, we thank sw0rdl1ght for bringing the .order_by() case to the attention of the security team.