VYPR
High severity7.3NVD Advisory· Published Feb 5, 2025· Updated Apr 15, 2026

CVE-2025-24372

CVE-2025-24372

Description

CKAN is an open-source DMS (data management system) for powering data hubs and data portals. Using a specially crafted file, a user could potentially upload a file containing code that when executed could send arbitrary requests to the server. If that file was opened by an administrator, it could lead to escalation of privileges of the original submitter or other malicious actions. Users must have been registered to the site to exploit this vulnerability. This vulnerability has been fixed in CKAN 2.10.7 and 2.11.2. Users are advised to upgrade. On versions prior to CKAN 2.10.7 and 2.11.2, site maintainers can restrict the file types supported for uploading using the ckan.upload.user.mimetypes / ckan.upload.user.types and ckan.upload.group.mimetypes / ckan.upload.group.types config options. To entirely disable file uploads users can use: ckan.upload.user.types = none

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
ckanPyPI
< 2.10.72.10.7
ckanPyPI
>= 2.11.0, < 2.11.22.11.2

Patches

4
9f2094b26721
5bd556eb4370
a4fc5e06634e

Update changelog with 2.10.7 and 2.11.2 entries

https://github.com/ckan/ckanamercaderFeb 5, 2025via ghsa
1 file changed · +70 0
  • CHANGELOG.rst+70 0 modified
    @@ -22,6 +22,41 @@ Migration notes
       the string ``*`` as value in both options (this is dangerous and
       **not** recommended).
     
    +v.2.11.2 2025-02-05
    +===================
    +
    +Migration notes
    +---------------
    +
    +* Going forward, if both ``ckan.upload.[type].mimetypes`` and
    +  ``ckan.upload.[type].types`` are empty, no uploads will be allowed
    +  for this object type (e.g. ``user`` or ``group``). It previoulsy
    +  meant that all file types were allowed. To keep the old behaviour use
    +  the string ``*`` as value in both options (this is dangerous and
    +  **not** recommended).
    +
    +Minor changes
    +-------------
    +
    +- Adapt login failure message if reCAPTCHA is enabled (`#8627
    +  <https://github.com/ckan/ckan/pull/8627>`_)
    +- Update release process docs (`#8586
    +  <https://github.com/ckan/ckan/pull/8586>`_)
    +
    +
    +Bugfixes
    +--------
    +
    +- `CVE-2025-24372 <https://github.com/ckan/ckan/security/advisories/GHSA-7pq5-qcp6-mcww>`_: Fix potential
    +  XSS vector through user and group/organization images.
    +- Invalidate cached pages and load fresh ones if cookies change (`#6955
    +  <https://github.com/ckan/ckan/pull/6955>`_)
    +- Fix `check_access` order for resource create view (`#8588
    +  <https://github.com/ckan/ckan/pull/8588>`_)
    +- Fix CSV export error by ensuring BOM is written correctly as a string for
    +  Excel compatibility. (`#8635 <https://github.com/ckan/ckan/pull/8635>`_)
    +- Fix auth check for datastore data dictionary view (`#8639
    +  <https://github.com/ckan/ckan/pull/8639>`_)
     
     
     v.2.11.1 2024-12-11
    @@ -690,6 +725,41 @@ Removals and deprecations
           class SecondPlugin(p.SingletonPlugin, BasePlutin):
               p.implements(IAnything)
     
    +
    +
    +v.2.10.7 2025-02-05
    +===================
    +
    +Migration notes
    +---------------
    +
    +* Going forward, if both ``ckan.upload.[type].mimetypes`` and
    +  ``ckan.upload.[type].types`` are empty, no uploads will be allowed
    +  for this object type (e.g. ``user`` or ``group``). It previoulsy
    +  meant that all file types were allowed. To keep the old behaviour use
    +  the string ``*`` as value in both options (this is dangerous and
    +  **not** recommended).
    +
    +Minor changes
    +-------------
    +- Adapt login failure message if reCAPTCHA is enabled (`#8627
    +  <https://github.com/ckan/ckan/pull/8627>`_)
    +- Update release process docs (`#8586
    +  <https://github.com/ckan/ckan/pull/8586>`_)
    +- Support 2.11 version of the Solr schema in CKAN 2.10 (``5acfeda6e``)
    +
    +  
    +Bugfixes
    +--------
    +- `CVE-2025-24372 <https://github.com/ckan/ckan/security/advisories/GHSA-7pq5-qcp6-mcww>`_: Fix potential
    +  XSS vector through user and group/organization images.
    +- Invalidate cached pages and load fresh ones if cookies change (`#6955
    +  <https://github.com/ckan/ckan/pull/6955>`_)
    +- Fix `check_access` order for resource create view (`#8588
    +  <https://github.com/ckan/ckan/pull/8588>`_)
    +- Fix auth check for datastore data dictionary view (`#8639
    +  <https://github.com/ckan/ckan/pull/8639>`_)
    +
     v.2.10.6 2024-12-11
     ===================
     
    
7da6a26c6183

Verify user,group/org images upload type, enforce extension

https://github.com/ckan/ckanamercaderFeb 5, 2025via ghsa
6 files changed · +146 24
  • CHANGELOG.rst+15 0 modified
    @@ -9,6 +9,21 @@ Changelog
     
     .. towncrier release notes start
     
    +v.2.12.0 (Not yet released)
    +===========================
    +
    +Migration notes
    +---------------
    +
    +* Going forward, if both ``ckan.upload.[type].mimetypes`` and
    +  ``ckan.upload.[type].types`` are empty, no uploads will be allowed
    +  for this object type (e.g. ``user`` or ``group``). It previoulsy
    +  meant that all file types were allowed. To keep the old behaviour use
    +  the string ``*`` as value in both options (this is dangerous and
    +  **not** recommended).
    +
    +
    +
     v.2.11.1 2024-12-11
     ===================
     
    
  • ckan/config/config_declaration.yaml+17 6 modified
    @@ -1328,25 +1328,36 @@ groups:
             type: list
             default: image
             example: image text
    -        description: File types allowed to upload as user's avatar. No restrictions applied when empty
    +        description: File types allowed to upload as user's avatar. If empty and :ref:`ckan.upload.user.mimetypes`
    +          is also empty, no uploads are allowed. To allow any kind of file upload, use the ``*`` string in both
    +          options (this is dangerous and **not** recommended). Note also that ``text/svg`` can contain embedded
    +          javascript code so it only should be used in trusted environments.
     
           - key: ckan.upload.user.mimetypes
             type: list
             default: image/png image/gif image/jpeg
    -        example: image/png text/svg
    -        description: File MIMETypes allowed to upload as user's avatar. No restrictions applied when empty
    +        example: image/png
    +        description: File MIMETypes allowed to upload as user's avatar. If empty and :ref:`ckan.upload.user.types`
    +          is also empty, no uploads are allowed. To allow any kind of file upload, use the ``*`` string in both
    +          options (this is dangerous and **not** recommended).
     
           - key: ckan.upload.group.types
             type: list
             default: image
             example: image text
    -        description: File types allowed to upload as group image. No restrictions applied when empty
    +        description: File types allowed to upload as group or organization image. If empty
    +          and :ref:`ckan.upload.group.mimetypes` is also empty, no uploads are allowed. To allow any kind of
    +          file upload, use the ``*`` string in both options (this is dangerous and **not** recommended).
     
           - key: ckan.upload.group.mimetypes
             type: list
             default: image/png image/gif image/jpeg
    -        example: image/png text/svg
    -        description: File MIMETypes allowed to upload as group image. No restrictions applied when empty
    +        example: image/png
    +        description: File MIMEtypes allowed to upload as group or organization image. If empty
    +          and :ref:`ckan.upload.group.types` is also empty, no uploads are allowed. To allow any kind of
    +          file upload, use the ``*`` string in both options (this is dangerous and **not** recommended).
    +          Note also that ``text/svg`` can contain embedded javascript code so it only should be used in
    +          trusted environments.
     
       - annotation: Webassets Settings
         options:
    
  • ckan/lib/uploader.py+54 13 modified
    @@ -7,6 +7,7 @@
     import logging
     import magic
     import mimetypes
    +from pathlib import Path
     from typing import Any, IO, Optional, Union
     from urllib.parse import urlparse
     
    @@ -159,10 +160,14 @@ def update_data_dict(self, data_dict: dict[str, Any], url_field: str,
                     self.filename = str(datetime.datetime.utcnow()) + self.filename
                     self.filename = munge.munge_filename_legacy(self.filename)
                     self.filepath = os.path.join(self.storage_path, self.filename)
    -                data_dict[url_field] = self.filename
                     self.upload_file = _get_underlying_file(
                         self.upload_field_storage)
                     self.tmp_filepath = self.filepath + '~'
    +
    +                self.verify_type()
    +
    +                data_dict[url_field] = self.filename
    +
             # keep the file if there has been no change
             elif self.old_filename and not self.old_filename.startswith('http'):
                 if not self.clear:
    @@ -177,7 +182,6 @@ def upload(self, max_size: int = 2) -> None:
             anything unless the request is actually good.
             max_size is size in MB maximum of the file'''
     
    -        self.verify_type()
     
             if self.filename:
                 assert self.upload_file and self.filepath
    @@ -202,29 +206,66 @@ def upload(self, max_size: int = 2) -> None:
                     pass
     
         def verify_type(self):
    -        if not self.filename or not self.upload_file:
    +
    +        if not self.upload_file:
                 return
     
    -        mimetypes = config.get(
    +        allowed_mimetypes = config.get(
                 f"ckan.upload.{self.object_type}.mimetypes")
    -        types = config.get(f"ckan.upload.{self.object_type}.types")
    -        if not mimetypes and not types:
    -            return
    +        allowed_types = config.get(f"ckan.upload.{self.object_type}.types")
    +        if not allowed_mimetypes and not allowed_types:
    +            raise logic.ValidationError(
    +                {
    +                    self.file_field: [f"No uploads allowed for object type {self.object_type}"]
    +                }
    +            )
    +
    +        # Check that the declared types in the request are supported
    +        declared_mimetype_from_filename = mimetypes.guess_type(
    +            self.upload_field_storage.filename
    +        )[0]
    +        declared_content_type = self.upload_field_storage.content_type
    +        for declared_mimetype in (
    +            declared_mimetype_from_filename,
    +            declared_content_type,
    +        ):
    +            if (
    +                declared_mimetype
    +                and allowed_mimetypes
    +                and allowed_mimetypes[0] != "*"
    +                and declared_mimetype not in allowed_mimetypes
    +            ):
    +                raise logic.ValidationError(
    +                    {
    +                        self.file_field: [
    +                            f"Unsupported upload type: {declared_mimetype}"
    +                        ]
    +                    }
    +                )
    +
    +        # Check that the actual type guessed from the contents is supported
    +        # (2KB required for detecting xlsx mimetype)
    +        content = self.upload_file.read(2048)
    +        guessed_mimetype = magic.from_buffer(content, mime=True)
     
    -        # 2KB required for detecting xlsx mimetype
    -        actual = magic.from_buffer(self.upload_file.read(2048), mime=True)
             self.upload_file.seek(0, os.SEEK_SET)
    +
             err: ErrorDict = {
    -            self.file_field: [f"Unsupported upload type: {actual}"]
    +            self.file_field: [f"Unsupported upload type: {guessed_mimetype}"]
             }
     
    -        if mimetypes and actual not in mimetypes:
    +        if allowed_mimetypes and allowed_mimetypes[0] != "*" and guessed_mimetype not in allowed_mimetypes:
                 raise logic.ValidationError(err)
     
    -        type_ = actual.split("/")[0]
    -        if types and type_ not in types:
    +        type_ = guessed_mimetype.split("/")[0]
    +        if allowed_types and allowed_types[0] != "*" and type_ not in allowed_types:
                 raise logic.ValidationError(err)
     
    +        preferred_extension = mimetypes.guess_extension(guessed_mimetype)
    +        if preferred_extension:
    +            self.filename = str(Path(self.filename).with_suffix(preferred_extension))
    +            self.filepath = str(Path(self.filepath).with_suffix(preferred_extension))
    +
     
     class ResourceUpload(object):
         mimetype: Optional[str]
    
  • ckan/tests/cli/test_clean.py+4 4 modified
    @@ -11,8 +11,8 @@ def test_output_if_there_are_not_invalid_users(self, cli):
             result = cli.invoke(ckan, ["clean", "users"])
             assert "No users were found with invalid images." in result.output
     
    -    @pytest.mark.ckan_config("ckan.upload.user.mimetypes", "")
    -    @pytest.mark.ckan_config("ckan.upload.user.types", "")
    +    @pytest.mark.ckan_config("ckan.upload.user.mimetypes", "*")
    +    @pytest.mark.ckan_config("ckan.upload.user.types", "*")
         def test_confirm_dialog_if_no_force(
             self, cli, monkeypatch, create_with_upload, faker, ckan_config
         ):
    @@ -54,8 +54,8 @@ def test_confirm_dialog_if_no_force(
             users = call_action("user_list")
             assert len(users) == 2
     
    -    @pytest.mark.ckan_config("ckan.upload.user.mimetypes", "")
    -    @pytest.mark.ckan_config("ckan.upload.user.types", "")
    +    @pytest.mark.ckan_config("ckan.upload.user.mimetypes", "*")
    +    @pytest.mark.ckan_config("ckan.upload.user.types", "*")
         def test_correct_users_are_deleted(
             self, cli, monkeypatch, create_with_upload, faker, ckan_config
         ):
    
  • ckan/tests/lib/test_uploader.py+1 1 modified
    @@ -90,7 +90,7 @@ def test_group_upload(self, monkeypatch, tmpdir, make_app, ckan_config, faker):
                      u'upload': FileStorage(
                          BytesIO(faker.image()),
                          filename=u'logo.png',
    -                     content_type=u'PNG'
    +                     content_type=u'image/png'
                      ),
                      u'name': u'test-group-upload'}
             group_upload = Upload(u'group')
    
  • ckan/tests/logic/action/test_create.py+55 0 modified
    @@ -2226,6 +2226,47 @@ def test_upload_non_picture_with_png_extension(
                     logic.ValidationError, match="Unsupported upload type"):
                 create_with_upload("hello world", "file.png", **params)
     
    +    @pytest.mark.ckan_config("ckan.upload.user.mimetypes", "")
    +    @pytest.mark.ckan_config("ckan.upload.user.types", "")
    +    def test_uploads_not_allowed_when_empty_mimetypes_and_types(
    +            self, create_with_upload, faker):
    +        params = {
    +            "name": faker.user_name(),
    +            "email": faker.email(),
    +            "password": "12345678",
    +            "action": "user_create",
    +            "upload_field_name": "image_upload",
    +        }
    +        with pytest.raises(
    +                logic.ValidationError, match="No uploads allowed for object type"):
    +            create_with_upload("hello world", "file.png", **params)
    +
    +    @pytest.mark.ckan_config("ckan.upload.user.mimetypes", "*")
    +    @pytest.mark.ckan_config("ckan.upload.user.types", "image")
    +    def test_upload_all_types_allowed_needs_both_options(self, create_with_upload, faker):
    +        params = {
    +            "name": faker.user_name(),
    +            "email": faker.email(),
    +            "password": "12345678",
    +            "action": "user_create",
    +            "upload_field_name": "image_upload",
    +        }
    +        with pytest.raises(
    +                logic.ValidationError, match="Unsupported upload type"):
    +            assert create_with_upload(faker.json(), "file.json", **params)
    +
    +    @pytest.mark.ckan_config("ckan.upload.user.mimetypes", "*")
    +    @pytest.mark.ckan_config("ckan.upload.user.types", "*")
    +    def test_upload_all_types_allowed(self, create_with_upload, faker):
    +        params = {
    +            "name": faker.user_name(),
    +            "email": faker.email(),
    +            "password": "12345678",
    +            "action": "user_create",
    +            "upload_field_name": "image_upload",
    +        }
    +        assert create_with_upload(faker.json(), "file.json", **params)
    +
         @pytest.mark.ckan_config("ckan.upload.user.types", "image")
         def test_upload_picture(self, create_with_upload, faker):
             params = {
    @@ -2237,6 +2278,20 @@ def test_upload_picture(self, create_with_upload, faker):
             }
             assert create_with_upload(faker.image(), "file.png", **params)
     
    +    @pytest.mark.ckan_config("ckan.upload.user.types", "image")
    +    def test_upload_picture_extension_enforced(self, create_with_upload, faker):
    +        params = {
    +            "name": faker.user_name(),
    +            "email": faker.email(),
    +            "password": "12345678",
    +            "action": "user_create",
    +            "upload_field_name": "image_upload",
    +        }
    +        user = create_with_upload(faker.image(image_format="jpeg"), "file.png", **params)
    +
    +        assert user["image_url"].endswith(".jpg")
    +        assert user["image_display_url"].endswith(".jpg")
    +
     
     class TestVocabularyCreate(object):
         @pytest.mark.usefixtures("non_clean_db")
    

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

9

News mentions

0

No linked articles in our index yet.