Skip to content

fix: sandbox served course assets to prevent stored XSS - #94

Merged
johanseto merged 1 commit into
open-release/teak.nelpfrom
jlc/backport-security-prevent-stored-XSS
Sep 29, 2026
Merged

johanseto merged 1 commit into
open-release/teak.nelpfrom
jlc/backport-security-prevent-stored-XSS

Conversation

@johanseto

@johanseto johanseto commented Sep 22, 2026 •

Copy link
Copy Markdown

This pull request introduces a security improvement to the way course assets are served by the contentserver, ensuring that uploaded assets such as HTML or SVG files are sandboxed by default to prevent cross-site scripting (XSS) attacks. It also adds a new feature flag, course_assets.allow_unsafe_asset_rendering, which allows this sandboxing to be disabled globally or on a per-course basis for exceptional cases. The changes are covered by new tests to verify the correct behavior of the sandbox header under different flag configurations.

Security improvements:

  • By default, all course asset responses now include a Content-Security-Policy: sandbox header, preventing uploaded assets from executing scripts in the Studio/LMS origin and mitigating stored XSS risks.

Feature flag introduction:

  • Added the course_assets.allow_unsafe_asset_rendering feature flag (a CourseWaffleFlag) with documentation, allowing the sandboxing protection to be selectively disabled for specific courses or globally if necessary.

Testing and validation:

  • Added comprehensive tests to ensure:
    • The sandbox header is present by default and removed when the flag is enabled globally or per-course.
    • The sandbox header is only removed for the correct course when a per-course override is used.
  • Introduced test utilities and imports to support the new tests, including override_waffle_flag, CourseKey, and WaffleFlagCourseOverrideModel.

Test

Before

2026-09-29_09-03

After

2026-09-29_09-02

Studio course assets are served by the contentserver with the uploader-supplied
Content-Type and no neutralizing headers, on a route mounted on the Studio (CMS)
origin. An author with file-upload permission can upload an HTML or SVG file
containing script; when another user opens the asset URL it runs same-origin
with the Studio session, enabling privilege escalation (self-granting
course-admin, or Django superuser via same-origin /admin/ when a global-staff
user views it).

Send `Content-Security-Policy: sandbox` on every course-asset response so the
asset loads in an opaque origin and cannot script against the Studio/LMS
session. A per-course escape-hatch flag, course_assets.allow_unsafe_asset_rendering,
lets operators temporarily disable sandboxing for a course whose content must be
migrated first.

Closes GHSA-c6xg-fh3c-vvhh.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
(cherry picked from commit b5fc56a)
@johanseto
johanseto merged commit 0ff545b into open-release/teak.nelp Sep 29, 2026
47 checks passed
@johanseto
johanseto deployed to open-release/teak.nelp September 29, 2026 14:09 — with GitHub Actions Active
@johanseto
johanseto deployed to open-release/teak.nelp September 29, 2026 14:10 — with GitHub Actions Active
@andrey-canon

Copy link
Copy Markdown

@johanseto did you include this in the doc ?

@johanseto

Copy link
Copy Markdown
Author

@johanseto did you include this in the doc ?

https://github.com/eduNEXT/edunext-nelp-documentation/pull/31

This branch was successfully deployed

1 active deployment
open-release/teak.nelp — 62b0f774 Deployed Sep 29, 2026 by johanseto via create-jira-issue / create_jira_issue #29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants