[Django] #36784: Add CSP support to Django's script object and media objects

32 views
Skip to first unread message

Django

unread,
Dec 8, 2025, 11:45:11 AM12/8/25
to django-...@googlegroups.com
#36784: Add CSP support to Django's script object and media objects
--------------------------------+-----------------------------------------
Reporter: Johannes Maron | Type: Uncategorized
Status: new | Component: Forms
Version: 6.0 | Severity: Normal
Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
--------------------------------+-----------------------------------------
Django 5.2 added official support for a script object in media classes
#35886

However, the introduction of CSP's nonce-function in Django 6.0 seems to
have overlooked both old form media rendering and the script-object.
Furthermore, the template processor-based approach currently doesn't
provide practical solution of object based media assets.

I'd suggest updating the media class and tag-rendering to include a nonce
values by default, or the least an opt-in that doesn't require the request
context in during form definition.

If there already is an easy way to add nonce-values to form media, I'd
suggest that we add a few lines of documentation for the next developer
looking for it.
--
Ticket URL: <https://code.djangoproject.com/ticket/36784>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
Dec 9, 2025, 10:35:42 AM12/9/25
to django-...@googlegroups.com
#36784: Add CSP support to Django's script object and media objects
--------------------------------+--------------------------------------
Reporter: Johannes Maron | Owner: (none)
Type: New feature | Status: new
Component: Forms | Version: 6.0
Severity: Normal | Resolution:
Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
--------------------------------+--------------------------------------
Changes (by Natalia Bidart):

* type: Uncategorized => New feature

Comment:

Hello Johannes! Thank you for this report. Could you please share a small
project sample that would highlight how CSP is lacking support for the
cases you listed? That would help me greatly to properly triage this
ticket.
--
Ticket URL: <https://code.djangoproject.com/ticket/36784#comment:1>

Django

unread,
Dec 9, 2025, 10:36:22 AM12/9/25
to django-...@googlegroups.com
#36784: Add CSP support to Django's script object and media objects
--------------------------------+--------------------------------------
Reporter: Johannes Maron | Owner: (none)
Type: New feature | Status: new
Component: Forms | Version: 6.0
Severity: Normal | Resolution:
Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
--------------------------------+--------------------------------------
Changes (by Natalia Bidart):

* cc: Rob Hudson (added)

Comment:

Adding Rob as cc for awareness.
--
Ticket URL: <https://code.djangoproject.com/ticket/36784#comment:2>

Django

unread,
Dec 9, 2025, 8:25:27 PM12/9/25
to django-...@googlegroups.com
#36784: Add CSP support to Django's script object and media objects
--------------------------------+------------------------------------
Reporter: Johannes Maron | Owner: (none)
Type: New feature | Status: new
Component: Forms | Version: 6.0
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
--------------------------------+------------------------------------
Changes (by Natalia Bidart):

* cc: Tobias Kunze, David Smith (added)
* stage: Unreviewed => Accepted

Comment:

I've been thinking about this and I see a couple of options:

* A decent workaround would be to define a template filter that would take
the nonce and include it in the tag. We could perhaps write a how-to to
backport and include in 6.0.
* For `main`, I agree that we should ideally have something more "first
class citizen" in the objects. I'm adding a few folks as cc to see what
they think.

Given the above, I'll accept pending a design discussion for the "new
feature" part for 6.1. In any case, Johannes it would be super helpful if
you could attach a minimal sample project showing the use cases.
--
Ticket URL: <https://code.djangoproject.com/ticket/36784#comment:3>

Django

unread,
Dec 10, 2025, 4:56:46 AM12/10/25
to django-...@googlegroups.com
#36784: Add CSP support to Django's script object and media objects
--------------------------------+------------------------------------
Reporter: Johannes Maron | Owner: (none)
Type: New feature | Status: new
Component: Forms | Version: 6.0
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
--------------------------------+------------------------------------
Comment (by Pravin):

Any thoughts on below failing testcase for above behaviour ?

{{{
from django.test import SimpleTestCase, override_settings
from django.forms import Form
from django.template import Context, Template
from django.utils.csp import CSP

class FormWithJsMedia(Form):
class Media:
js = ["path/to/js_file.js"]

@override_settings(
STATIC_URL="/static/",
MIDDLEWARE=[
"django.middleware.security.SecurityMiddleware",
"django.middleware.csp.ContentSecurityPolicyMiddleware",
],
TEMPLATES=[{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.request",
"django.template.context_processors.csp",
],
},
}],
SECURE_CSP={
"default-src": [CSP.SELF],
"script-src": [CSP.SELF, CSP.NONCE],
}
)
class CSPMediaTest(SimpleTestCase):
def test_form_media_js_missing_nonce(self):
form = FormWithJsMedia()
tpl = Template("{% load static %}{{ form.media }}")
rendered = tpl.render(Context({"form": form}))
self.assertIn('<script src="/static/path/to/js_file.js">',
rendered)
self.assertIn('nonce="', rendered)

}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/36784#comment:4>

Django

unread,
Dec 10, 2025, 1:33:33 PM12/10/25
to django-...@googlegroups.com
#36784: Add CSP support to Django's script object and media objects
--------------------------------+------------------------------------
Reporter: Johannes Maron | Owner: Rish
Type: New feature | Status: assigned
Component: Forms | Version: 6.0
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
--------------------------------+------------------------------------
Changes (by Rish):

* owner: (none) => Rish
* status: new => assigned

--
Ticket URL: <https://code.djangoproject.com/ticket/36784#comment:5>

Django

unread,
Dec 10, 2025, 7:10:31 PM12/10/25
to django-...@googlegroups.com
#36784: Add CSP support to Django's script object and media objects
--------------------------------+------------------------------------
Reporter: Johannes Maron | Owner: Rish
Type: New feature | Status: assigned
Component: Forms | Version: 6.0
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
--------------------------------+------------------------------------
Comment (by Rob Hudson):

The challenge seems to be that `form.media` does not have access to the
context and is stateless. I assume this is by design. Changing this seems
like a big architectural shift so I looked for other options.

One idea that I liked has two parts to it:

1. Extend the `Script` class to add a `with_nonce: bool = False`
parameter.

Example:

{{{
class MyWidget(forms.TextInput):
class Media:
js = [
"already-in-policy.js", # No nonce needed
Script("inline-script.js", with_nonce=True), # Opt-in to
nonce
]
}}}

This would render the script tag with a data attribute - something
harmless if the next step is forgotten (vs something like a nonce
attribute with a sentinel):
{{{
<script src="..." data-csp-nonce></script>
}}}

I like the opt-in nature of this vs outputting all tags with a data
attribute since, if the media is self served you likely don't need the
nonce.

2. Use a template filter to replace data attribute with the actual nonce

{{{
{{ form.media|with_nonce }}
}}}

The filter:
- finds and replaces the `data-csp-nonce` attribute with the actual nonce
from template context.
- if no nonce in the context, removes the data attribute.
--
Ticket URL: <https://code.djangoproject.com/ticket/36784#comment:6>

Django

unread,
Dec 11, 2025, 5:55:48 AM12/11/25
to django-...@googlegroups.com
#36784: Add CSP support to Django's script object and media objects
--------------------------------+------------------------------------
Reporter: Johannes Maron | Owner: Rish
Type: New feature | Status: assigned
Component: Forms | Version: 6.0
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
--------------------------------+------------------------------------
Comment (by Johannes Maron):

@Rish, if you don't mind, I was hoping to solve this myself. Did you make
any progress yet, you'd care to share?

@Rob, I was thinking to use template nodes, instead of HTML-safe strings.
So the asset objects would be rendered with the full temple context,
including a nouce.
If the template includes it, we render it. Otherwise we don't. Of course,
this could be added explicitly with a keyword, as you suggested.
--
Ticket URL: <https://code.djangoproject.com/ticket/36784#comment:7>

Django

unread,
Dec 19, 2025, 2:13:35 PM12/19/25
to django-...@googlegroups.com
#36784: Add CSP support to Django's script object and media objects
--------------------------------+------------------------------------
Reporter: Johannes Maron | Owner: Rish
Type: New feature | Status: assigned
Component: Forms | Version: 6.0
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
--------------------------------+------------------------------------
Comment (by Rish):

Replying to [comment:7 Johannes Maron]:
> @Rish, if you don't mind, I was hoping to solve this myself. Did you
make any progress yet, you'd care to share?
>
> @Rob, I was thinking to use template nodes, instead of HTML-safe
strings. So the asset objects would be rendered with the full temple
context, including a nouce.
> If the template includes it, we render it. Otherwise we don't. Of
course, this could be added explicitly with a keyword, as you suggested.

Sorry for blocking you, I am new to this. You can have the ticket.
--
Ticket URL: <https://code.djangoproject.com/ticket/36784#comment:8>

Django

unread,
Dec 19, 2025, 2:13:58 PM12/19/25
to django-...@googlegroups.com
#36784: Add CSP support to Django's script object and media objects
--------------------------------+------------------------------------
Reporter: Johannes Maron | Owner: (none)
Type: New feature | Status: new
Component: Forms | Version: 6.0
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
--------------------------------+------------------------------------
Changes (by Rish):

* owner: Rish => (none)
* status: assigned => new

--
Ticket URL: <https://code.djangoproject.com/ticket/36784#comment:9>

Django

unread,
Dec 29, 2025, 8:18:40 AM12/29/25
to django-...@googlegroups.com
#36784: Add CSP support to Django's script object and media objects
--------------------------------+-----------------------------------------
Reporter: Johannes Maron | Owner: Nilesh Pahari
Type: New feature | Status: assigned
Component: Forms | Version: 6.0
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
--------------------------------+-----------------------------------------
Changes (by Nilesh Pahari):

* owner: (none) => Nilesh Pahari
* status: new => assigned

--
Ticket URL: <https://code.djangoproject.com/ticket/36784#comment:10>

Django

unread,
Dec 30, 2025, 10:57:59 AM12/30/25
to django-...@googlegroups.com
#36784: Add CSP support to Django's script object and media objects
--------------------------------+-----------------------------------------
Reporter: Johannes Maron | Owner: Nilesh Pahari
Type: New feature | Status: assigned
Component: Forms | Version: 6.0
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
--------------------------------+-----------------------------------------
Comment (by Laharyy):

Replying to [comment:10 Nilesh Pahari]: Hi, I noticed this ticket is
currently assigned.

I’m interested in working on this issue and have started reviewing the
Media
and script rendering internals. Please let me know if anyone is actively
working on it; otherwise I’d be happy to take this forward.
--
Ticket URL: <https://code.djangoproject.com/ticket/36784#comment:11>

Django

unread,
Dec 30, 2025, 11:07:50 AM12/30/25
to django-...@googlegroups.com
#36784: Add CSP support to Django's script object and media objects
--------------------------------+-----------------------------------------
Reporter: Johannes Maron | Owner: Nilesh Pahari
Type: New feature | Status: assigned
Component: Forms | Version: 6.0
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
--------------------------------+-----------------------------------------
Comment (by Nilesh Pahari):

Replying to [comment:11 Laharyy]:
> Replying to [comment:10 Nilesh Pahari]: Hi, I noticed this ticket
is currently assigned.
>
> I’m interested in working on this issue and have started reviewing the
Media
> and script rendering internals. Please let me know if anyone is actively
> working on it; otherwise I’d be happy to take this forward.
>
Hi, thanks for your interest. I’m currently working on this, but I’ll
definitely let you know if I need any help.
--
Ticket URL: <https://code.djangoproject.com/ticket/36784#comment:12>

Django

unread,
Jan 1, 2026, 4:14:59 PMJan 1
to django-...@googlegroups.com
#36784: Add CSP support to Django's script object and media objects
--------------------------------+-----------------------------------------
Reporter: Johannes Maron | Owner: Nilesh Pahari
Type: New feature | Status: assigned
Component: Forms | Version: 6.0
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
--------------------------------+-----------------------------------------
Comment (by Nilesh Pahari):

Hi @Laharyy, this is taking a bit longer than I initially anticipated. If
you’re particularly interested, you’re welcome to take this up. I’m still
working on it and may open a PR in the coming days otherwise.
--
Ticket URL: <https://code.djangoproject.com/ticket/36784#comment:13>

Django

unread,
Feb 24, 2026, 3:25:47 PMFeb 24
to django-...@googlegroups.com
#36784: Add CSP support to Django's script object and media objects
--------------------------------+------------------------------------------
Reporter: Johannes Maron | Owner: Johannes Maron
Type: New feature | Status: assigned
Component: Forms | Version: 6.0
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
--------------------------------+------------------------------------------
Changes (by Johannes Maron):

* owner: Nilesh Pahari => Johannes Maron

Comment:

Hi there,

Since I opened it and am fairly familiar with this part of the code base,
I am taking the liberty to submit a patch myself. I hope y'all don't mind
<3

Cheers!
Joe
--
Ticket URL: <https://code.djangoproject.com/ticket/36784#comment:14>

Django

unread,
Feb 24, 2026, 4:24:28 PMFeb 24
to django-...@googlegroups.com
#36784: Add CSP support to Django's script object and media objects
--------------------------------+------------------------------------------
Reporter: Johannes Maron | Owner: Johannes Maron
Type: New feature | Status: assigned
Component: Forms | Version: 6.0
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 1
Easy pickings: 0 | UI/UX: 0
--------------------------------+------------------------------------------
Changes (by Johannes Maron):

* has_patch: 0 => 1
* needs_better_patch: 0 => 1

--
Ticket URL: <https://code.djangoproject.com/ticket/36784#comment:15>

Django

unread,
Feb 25, 2026, 1:18:30 PMFeb 25
to django-...@googlegroups.com
#36784: Add CSP support to Django's script object and media objects
--------------------------------+------------------------------------------
Reporter: Johannes Maron | Owner: Johannes Maron
Type: New feature | Status: assigned
Component: Forms | Version: 6.0
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
--------------------------------+------------------------------------------
Changes (by Johannes Maron):

* needs_better_patch: 1 => 0

--
Ticket URL: <https://code.djangoproject.com/ticket/36784#comment:16>

Django

unread,
Mar 5, 2026, 5:16:03 PMMar 5
to django-...@googlegroups.com
#36784: Add CSP support to Django's script object and media objects
--------------------------------+------------------------------------------
Reporter: Johannes Maron | Owner: Johannes Maron
Type: New feature | Status: assigned
Component: Forms | Version: 6.0
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 1
Easy pickings: 0 | UI/UX: 0
--------------------------------+------------------------------------------
Changes (by Jacob Walls):

* needs_better_patch: 0 => 1

--
Ticket URL: <https://code.djangoproject.com/ticket/36784#comment:17>

Django

unread,
Mar 6, 2026, 8:41:05 AMMar 6
to django-...@googlegroups.com
#36784: Add CSP support to Django's script object and media objects
--------------------------------+------------------------------------------
Reporter: Johannes Maron | Owner: Johannes Maron
Type: New feature | Status: assigned
Component: Forms | Version: 6.0
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
--------------------------------+------------------------------------------
Changes (by Johannes Maron):

* needs_better_patch: 1 => 0

--
Ticket URL: <https://code.djangoproject.com/ticket/36784#comment:18>

Django

unread,
Mar 12, 2026, 6:59:54 PM (14 days ago) Mar 12
to django-...@googlegroups.com
#36784: Add CSP support to Django's script object and media objects
--------------------------------+------------------------------------------
Reporter: Johannes Maron | Owner: Johannes Maron
Type: New feature | Status: assigned
Component: Forms | Version: 6.0
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 1
Easy pickings: 0 | UI/UX: 0
--------------------------------+------------------------------------------
Changes (by Jacob Walls):

* needs_better_patch: 0 => 1

--
Ticket URL: <https://code.djangoproject.com/ticket/36784#comment:19>

Django

unread,
Mar 12, 2026, 9:35:53 PM (14 days ago) Mar 12
to django-...@googlegroups.com
#36784: Add CSP support to Django's script object and media objects
--------------------------------+------------------------------------------
Reporter: Johannes Maron | Owner: Johannes Maron
Type: New feature | Status: assigned
Component: Forms | Version: 6.0
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 1
Easy pickings: 0 | UI/UX: 0
--------------------------------+------------------------------------------
Comment (by Natalia Bidart):

I've left a note on the PR, but wanted to expand here on the design
question. My recommendation is to go with a more explicit approach: I've
been brainstorming with some LLMs and investigating different paths. The
one I settled on is having a `render(attrs=None)` method on `Script` and
`Media` classes, paired with a template filter that passes the nonce
explicitly. This keeps CSP and form media as independent concerns (which I
think it's important), the rendering machinery stays generic, and the
filter is the only place that knows a nonce is involved and connects the
two worlds.

My rationale is that both CSP and form media are opt-in features, and I
think they should be combined explicitly and not behind the scenes, this
is why I propose a filter since it makes the intent visible at the call
site. Rob's suggestion in comment:6 points in the right direction, though
I'd build on it as follows: rather than a boolean flag on `Script`, let's
add a generic `attrs` dict parameter in `render`, since this is more
consistent with `Widget.render(attrs=...)` elsewhere in `django.forms`,
and is more extensible (and nonce-agnostic). Then the filter bridges both
sides:

{{{
{{ form.media|with_nonce:csp_nonce }}
}}}

On the filter vs. tag question: yes, a filter cannot access the template
context directly, so the nonce must be passed explicitly as the filter
argument. For me, that's actually a (required) feature: it makes the
machinery explicit and works regardless of what the variable is named in
the context (think about an alternative implementation of CSP or a
different nonce generator).

Rough sketch (names and logic to be polished):
{{{#!diff
diff --git a/django/forms/widgets.py b/django/forms/widgets.py
index 1bcfeba288..db47f0f1a2 100644
--- a/django/forms/widgets.py
+++ b/django/forms/widgets.py
@@ -82,15 +82,18 @@ class MediaAsset:
return hash(self._path)

def __str__(self):
+ return self.render()
+
+ def __repr__(self):
+ return f"{type(self).__qualname__}({self._path!r})"
+
+ def render(self, *, attrs=None):
return format_html(
self.element_template,
path=self.path,
- attributes=flatatt(self.attributes),
+ attributes=flatatt({**(attrs or {}), **self.attributes}),
)

- def __repr__(self):
- return f"{type(self).__qualname__}({self._path!r})"
-
@property
def path(self):
"""
@@ -142,38 +145,47 @@ class Media:
def _js(self):
return self.merge(*self._js_lists)

- def render(self):
+ def render(self, *, attrs=None):
return mark_safe(
"\n".join(
chain.from_iterable(
- getattr(self, "render_" + name)() for name in
MEDIA_TYPES
+ getattr(self, "render_" + name)(attrs=attrs) for name
in MEDIA_TYPES
)
)
)

- def render_js(self):
+ def render_js(self, *, attrs=None):
return [
(
- path.__html__()
- if hasattr(path, "__html__")
- else format_html('<script src="{}"></script>',
self.absolute_path(path))
+ path.render(attrs=attrs)
+ if isinstance(path, MediaAsset)
+ else (
+ path.__html__()
+ if hasattr(path, "__html__")
+ else
Script(self.absolute_path(path)).render(attrs=attrs)
+ )
)
for path in self._js
]

- def render_css(self):
+ def render_css(self, *, attrs=None):
# To keep rendering order consistent, we can't just iterate over
# items(). We need to sort the keys, and iterate over the sorted
list.
media = sorted(self._css)
return chain.from_iterable(
[
(
- path.__html__()
- if hasattr(path, "__html__")
- else format_html(
- '<link href="{}" media="{}" rel="stylesheet">',
- self.absolute_path(path),
- medium,
+ path.render(attrs=attrs)
+ if isinstance(path, MediaAsset)
+ else (
+ path.__html__()
+ if hasattr(path, "__html__")
+ else format_html(
+ '<link href="{}" media="{}" {}
rel="stylesheet">',
+ self.absolute_path(path),
+ medium,
+ flatatt(attrs or {}),
+ )
)
)
for path in self._css[medium]
diff --git a/django/templatetags/media.py b/django/templatetags/media.py
new file mode 100644
index 0000000000..c9c84e9042
--- /dev/null
+++ b/django/templatetags/media.py
@@ -0,0 +1,16 @@
+from django import template
+
+register = template.Library()
+
+
+...@register.filter
+def with_nonce(media, nonce):
+ """
+ Render a Media object with a CSP nonce applied to all script and link
tags.
+
+ Usage::
+
+ {% load media %}
+ {{ form.media|with_nonce:csp_nonce }}
+ """
+ return media.render(attrs={"nonce": nonce} if nonce else None)
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/36784#comment:20>

Django

unread,
Mar 17, 2026, 2:22:48 PM (9 days ago) Mar 17
to django-...@googlegroups.com
#36784: Add CSP support to Django's script object and media objects
--------------------------------+------------------------------------------
Reporter: Johannes Maron | Owner: Johannes Maron
Type: New feature | Status: assigned
Component: Forms | Version: 6.0
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 1
Easy pickings: 0 | UI/UX: 0
--------------------------------+------------------------------------------
Comment (by Jacob Walls):

I find the reasoning behind Natalia's proposal persuasive, and I also like
the parallel explicitness with the explicit provision of `{{ csp_nonce }}`
in `<script>` tags.
--
Ticket URL: <https://code.djangoproject.com/ticket/36784#comment:21>

Django

unread,
Mar 23, 2026, 8:39:43 AM (3 days ago) Mar 23
to django-...@googlegroups.com
#36784: Add CSP support to Django's script object and media objects
--------------------------------+------------------------------------------
Reporter: Johannes Maron | Owner: Johannes Maron
Type: New feature | Status: assigned
Component: Forms | Version: 6.0
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 1
Easy pickings: 0 | UI/UX: 0
--------------------------------+------------------------------------------
Changes (by Carsten Fuchs):

* cc: Carsten Fuchs (added)

--
Ticket URL: <https://code.djangoproject.com/ticket/36784#comment:22>

Django

unread,
Mar 24, 2026, 7:44:53 PM (2 days ago) Mar 24
to django-...@googlegroups.com
#36784: Add CSP support to Django's script object and media objects
--------------------------------+------------------------------------------
Reporter: Johannes Maron | Owner: Natalia Bidart
Type: New feature | Status: assigned
Component: Forms | Version: 6.0
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 1
Easy pickings: 0 | UI/UX: 0
--------------------------------+------------------------------------------
Changes (by Natalia Bidart):

* owner: Johannes Maron => Natalia Bidart

Comment:

Given that I have a draft branch for the solution I proposed above, I may
take ownership of the ticket and polish the PR. @codingjoe I would
appreciate if you would be able to provide reviews!
--
Ticket URL: <https://code.djangoproject.com/ticket/36784#comment:23>

Django

unread,
Mar 25, 2026, 4:13:31 AM (yesterday) Mar 25
to django-...@googlegroups.com
#36784: Add CSP support to Django's script object and media objects
--------------------------------+------------------------------------------
Reporter: Johannes Maron | Owner: Johannes Maron
Type: New feature | Status: assigned
Component: Forms | Version: 6.0
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 1
Easy pickings: 0 | UI/UX: 0
--------------------------------+------------------------------------------
Changes (by Johannes Maron):

* owner: Natalia Bidart => Johannes Maron

Comment:

Hi there,

Thank you for your patience. I have a newborn at home and don't get to
work on Django every day.

A separate tag was my initial solution before changing it to a more
"magical" solution based on community feedback.

Since I only need to revert the changes that I already have, I would very
much appreciate continuing to work on this myself. Natalia, please reopen
my initial PR so we don't lose the history for any reviewer.

Lastly, I don't feel comfortable moving forward without a decision from
the steering committee. There has been too much back and forth on
potential solutions.
Especially a filter solution has sizable architectural implications, which
I will try to outline for the committee later today.

Best
Joe
--
Ticket URL: <https://code.djangoproject.com/ticket/36784#comment:24>

Django

unread,
Mar 25, 2026, 6:41:38 AM (yesterday) Mar 25
to django-...@googlegroups.com
#36784: Add CSP support to Django's script object and media objects
--------------------------------+------------------------------------------
Reporter: Johannes Maron | Owner: Johannes Maron
Type: New feature | Status: assigned
Component: Forms | Version: 6.0
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 1
Easy pickings: 0 | UI/UX: 0
--------------------------------+------------------------------------------
Comment (by Johannes Maron):

== Request for Comment: CSP nonce in form media

**Goal:** We want to provide a way to render form media with CSP nonce
values (currently impossible).

There are multiple ways to go about this, all with their pros and cons. We
should put a strong emphasis on dev usability (for people with deadlines)
while weighing the security considerations (marked with an **(S)**).
Importantly, any approach (other than a tag) may set a precedent and must
be considered beyond the scope of this ticket.

I would kindly ask the steering council and the security team for an
official comment, including a short explanation for future reference.

=== Tag-based

{{{
{% with_nonce form.media %}
}}}

||= Pros =||= Cons =||
|| No changes to the template engine are required. || Requires updates to
admin templates & 3rd-party packages. ||
|| Consistent with current logic, that rendering is handled in tags, like
`csrf`. || Fairly code-intense in Django. ||
|| **(S)** Explicit choice to add nonce values to form media. || ||

=== Filter-based w/ explicit nonce

{{{
{% if csp_nonce %}
{{ form.media|with_nonce:csp_nonce }}
{% endif %}

<!-- or -->

{% if csp_nonce %}
{{ form.media|context:csp_nonce }}
{% endif %}
}}}

||= Pros =||= Cons =||
|| No changes to the template engine are required. || Requires updates to
admin templates & 3rd-party packages. ||
|| **(S)** Explicit choice to add nonce values to form media. || Requires
case handling to prevent `VariableDoesNotExist` in Django's admin and 3rd-
party packages. (The context processor needs to be added to a project.)
||
|| || Fairly complex template syntax, including branching. ||



=== Filter-based w/ implicit context

{{{
{{ form.media|with_nonce }}
<!-- or -->
{{ form.media|context:"csp_nonce" }}
}}}

||= Pros =||= Cons =||
|| **(S)** Explicit choice to add nonce values to form media. || Requires
updates to admin templates & 3rd-party packages. ||
|| A `context` filter would be reusable. || A `context` filter would be
reusable and requires some form of a public interface. ||
|| || **(S)** Requires changes to the template engines. Filters are
currently not context-aware. ||

=== Automatic injection (if nonce in context)

{{{
{{ form.media }}
}}}

||= Pros =||= Cons =||
|| No updates to existing templates required (incl. 3rd party). || **(S)**
No explicit opt-in `nonce` in form media. However, the context processor
and the nonce option in CSP need to be enabled. ||
|| Simple (as is) syntax. || **(S)** Requires a new "special" object that
gets rendered with a nonce. ||

=== Author's note

I have implemented all versions and don't have a strong preference. Tag-
based seems the most in line with Django's current idioms, yet I do like
the simplicity of the automatic approach. Both filter approaches come with
a fair bit of complexity for either Django or its users, which is why I,
personally, wouldn't endorse them. The tag-based implementation was my
first approach; however, it does require more new code than any other
solution (similar to CSRF).
--
Ticket URL: <https://code.djangoproject.com/ticket/36784#comment:25>

Django

unread,
Mar 25, 2026, 8:16:21 AM (yesterday) Mar 25
to django-...@googlegroups.com
#36784: Add CSP support to Django's script object and media objects
--------------------------------+------------------------------------------
Reporter: Johannes Maron | Owner: Johannes Maron
Type: New feature | Status: assigned
Component: Forms | Version: 6.0
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 1
Easy pickings: 0 | UI/UX: 0
--------------------------------+------------------------------------------
Comment (by Jacob Walls):

Can I ask for some clarification on the security angle? It seems all of
the "cons" reduce to the proposition that we ''trust'' at least some
portion of the `request.context`. (Either potentially *any* key with a
reusable `context` filter, or just a hard-coded key for csp nonces.) I
thought `request.context` was already trusted, so I'm having to grasp at
straws to imagine the concern: is it that in a stack of reusable apps not
totally under your control, you cannot reason about whether or not the
contents of `request.context` have been sanitized if user-controlled? Or
something else?

----
I'm glad to have the Steering Council's eyes here to ratify an approach,
as I'm very keen to advance this for 6.1 (feature freeze mid-May).
--
Ticket URL: <https://code.djangoproject.com/ticket/36784#comment:26>

Django

unread,
Mar 25, 2026, 9:14:41 AM (yesterday) Mar 25
to django-...@googlegroups.com
#36784: Add CSP support to Django's script object and media objects
--------------------------------+------------------------------------------
Reporter: Johannes Maron | Owner: Johannes Maron
Type: New feature | Status: assigned
Component: Forms | Version: 6.0
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 1
Easy pickings: 0 | UI/UX: 0
--------------------------------+------------------------------------------
Comment (by Timothy Schilling):

I think for most Django devs who are not super familiar with CSP, but
still want to build out robust applications, avoiding `{{
form.media|with_nonce:csp_nonce }}` would be ideal.
[https://discord.com/channels/856567261900832808/859997770274045954/1476226860705644795
On the Django Discord], there were several long-time django devs who
agreed that the automatic injection of the nonce would be a preferable
API, with nobody preferring the explicit template tag.
--
Ticket URL: <https://code.djangoproject.com/ticket/36784#comment:27>

Django

unread,
Mar 25, 2026, 9:29:41 AM (yesterday) Mar 25
to django-...@googlegroups.com
#36784: Add CSP support to Django's script object and media objects
--------------------------------+------------------------------------------
Reporter: Johannes Maron | Owner: Johannes Maron
Type: New feature | Status: assigned
Component: Forms | Version: 6.0
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 1
Easy pickings: 0 | UI/UX: 0
--------------------------------+------------------------------------------
Comment (by Johannes Maron):

Hi Jacob,

hm… I hoped to point to more cons than just security considerations in my
previous comment. If you are referring to my deliberation on the PR, yes,
that one is a little trickier.
I believe my point isn't "can we trust the context" (We don't; that's why
we're escaping template variables.) – It's rather, can we trust everyone
with the context? A radical example would be changing `__html__` to always
ingest the full context. I would consider this VERY unsafe (to an
injection attack). We should always explicitly limit the context, but
there are multiple ways to do it.

Unrelated to the context, my other concern was that you might not trust a
3rd party to use safe script sources. I may trust the package, but not its
supply chain. E.G., Django's GeoAdmin uses scripts from a CDN, which opens
the door to a supply chain attack. The automatic solution would be to
unknowingly trust those resources. It does go against the idea of CSP a
little, where you want to explicitly review and whitelist browser
resources.

My main concern with any solution is making any changes to the template
engine. Both Django and Jinja had their fair share of security
vulnerabilities in their early days. New code simply means a new
opportunity to screw up. I consider myself experienced enough to know that
I make mistakes :P

Lastly, yes, 6.1 would be great, since this has been a bit of a pain point
in multiple issues. But Django has thought of patience. ;)

Hi Tim,

Yes, that's why I emphasized the "people with deadlines" part. It should
be easy to do the right (secure) thing. Now we just need to figure out
what that is.

Cheers,
Joe
--
Ticket URL: <https://code.djangoproject.com/ticket/36784#comment:28>

Django

unread,
Mar 25, 2026, 11:32:00 AM (yesterday) Mar 25
to django-...@googlegroups.com
#36784: Add CSP support to Django's script object and media objects
--------------------------------+------------------------------------------
Reporter: Johannes Maron | Owner: Johannes Maron
Type: New feature | Status: assigned
Component: Forms | Version: 6.0
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 1
Easy pickings: 0 | UI/UX: 0
--------------------------------+------------------------------------------
Comment (by Natalia Bidart):

Thank you everyone for the further commentary.

Given that there is a closely related ticket (#36825) covering the same
problem space from the admin's angle, and that Trac is not the best venue
to gather broad community input on a design question of this scope
(audience here is very limited), I will open a Django Forum post to
consolidate and continue the discussion. A link will be added here once it
is up, and I would kindly ask everyone to follow up there. The Security
team and SC are present on that platform and more "pingeable", while the
broader community can also contribute to the conversation.
--
Ticket URL: <https://code.djangoproject.com/ticket/36784#comment:29>

Django

unread,
Mar 25, 2026, 1:29:01 PM (yesterday) Mar 25
to django-...@googlegroups.com
#36784: Add CSP support to Django's script object and media objects
--------------------------------+------------------------------------------
Reporter: Johannes Maron | Owner: Johannes Maron
Type: New feature | Status: assigned
Component: Forms | Version: 6.0
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 1
Easy pickings: 0 | UI/UX: 0
--------------------------------+------------------------------------------
Comment (by Natalia Bidart):

Forum post here: https://forum.djangoproject.com/t/csp-nonce-support-for-
form-media-classes-and-admin-scripts/44698
--
Ticket URL: <https://code.djangoproject.com/ticket/36784#comment:30>
Reply all
Reply to author
Forward
0 new messages