Moderate severityNVD Advisory· Published Mar 13, 2024· Updated Aug 21, 2024
Potential log injection in reset user endpoint in ckan
CVE-2024-27097
Description
A user endpoint didn't perform filtering on an incoming parameter, which was added directly to the application log. This could lead to an attacker injecting false log entries or corrupt the log file format. This has been fixed in the CKAN versions 2.9.11 and 2.10.4. Users are advised to upgrade. Users unable to upgrade should override the /user/reset endpoint to filter the id parameter in order to exclude newlines.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
ckanPyPI | < 2.9.11 | 2.9.11 |
ckanPyPI | >= 2.10.0, < 2.10.4 | 2.10.4 |
Affected products
1Patches
381b56c55e5e3Merge pull request from GHSA-8g38-3m6v-232j
2 files changed · +14 −4
ckan/common.py+9 −0 modified@@ -306,6 +306,15 @@ def aslist(obj: Any, sep: Optional[str] = None, strip: bool = True) -> Any: return [obj] +def repr_untrusted(danger: Any): + """ + repr-format danger and truncate e.g. for logging untrusted input + """ + r = repr(danger) + rtrunc = r[:200] + return rtrunc + '…' if r != rtrunc else r + + local = Local() # This a proxy to the bounded config object
ckan/views/user.py+5 −4 modified@@ -25,7 +25,8 @@ import ckan.plugins as plugins from ckan import authz from ckan.common import ( - _, config, g, request, current_user, login_user, logout_user, session + _, config, g, request, current_user, login_user, logout_user, session, + repr_untrusted ) from ckan.types import Context, Schema, Response from ckan.lib import signals @@ -675,7 +676,7 @@ def post(self) -> Response: if id in (None, u''): h.flash_error(_(u'Email is required')) return h.redirect_to(u'user.request_reset') - log.info(u'Password reset requested for user "{}"'.format(id)) + log.info('Password reset requested for user %s', repr_untrusted(id)) context: Context = { 'user': current_user.name, @@ -716,8 +717,8 @@ def post(self) -> Response: pass if not user_objs: - log.info(u'User requested reset link for unknown user: {}' - .format(id)) + log.info('User requested reset link for unknown user: %s', + repr_untrusted(id)) for user_obj in user_objs: log.info(u'Emailing reset link to user: {}'
2 files changed · +14 −2
ckan/common.py+9 −0 modified@@ -261,6 +261,15 @@ def aslist(obj: Any, sep: Optional[str] = None, strip: bool = True) -> Any: return [obj] +def repr_untrusted(danger: Any): + """ + repr-format danger and truncate e.g. for logging untrusted input + """ + r = repr(danger) + rtrunc = r[:200] + return rtrunc + '…' if r != rtrunc else r + + local = Local() # This a proxy to the bounded config object
ckan/views/user.py+5 −2 modified@@ -24,7 +24,8 @@ import ckan.plugins as plugins from ckan import authz from ckan.common import ( - _, config, g, request, current_user, login_user, logout_user, session + _, config, g, request, current_user, login_user, logout_user, session, + repr_untrusted ) from ckan.types import Context, Schema, Response from ckan.lib import signals @@ -649,7 +650,7 @@ def post(self) -> Response: if id in (None, u''): h.flash_error(_(u'Email is required')) return h.redirect_to(u'user.request_reset') - log.info(u'Password reset requested for user "{}"'.format(id)) + log.info(u'Password reset requested for user %s', repr_untrusted(id)) context = cast( Context, { @@ -692,6 +693,8 @@ def post(self) -> Response: pass if not user_objs: + log.info(u'User requested reset link for unknown user: %s', + repr_untrusted(id)) log.info(u'User requested reset link for unknown user: {}' .format(id))
2 files changed · +13 −4
ckan/common.py+9 −0 modified@@ -197,6 +197,15 @@ def _get_session(): return pylons.session +def repr_untrusted(danger): + """ + repr-format danger and truncate e.g. for logging untrusted input + """ + r = repr(danger) + rtrunc = r[:200] + return rtrunc + '…' if r != rtrunc else r + + local = Local() # This a proxy to the bounded config object
ckan/views/user.py+4 −4 modified@@ -18,7 +18,7 @@ import ckan.model as model import ckan.plugins as plugins from ckan import authz -from ckan.common import _, config, g, request +from ckan.common import _, config, g, request, repr_untrusted log = logging.getLogger(__name__) @@ -613,7 +613,7 @@ def post(self): if id in (None, u''): h.flash_error(_(u'Email is required')) return h.redirect_to(u'/user/reset') - log.info(u'Password reset requested for user "{}"'.format(id)) + log.info(u'Password reset requested for user %s', repr_untrusted(id)) context = {u'model': model, u'user': g.user, u'ignore_auth': True} user_objs = [] @@ -647,8 +647,8 @@ def post(self): user_objs.append(user_obj) if not user_objs: - log.info(u'User requested reset link for unknown user: {}' - .format(id)) + log.info(u'User requested reset link for unknown user: %s', + repr_untrusted(id)) for user_obj in user_objs: log.info(u'Emailing reset link to user: {}'
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
7- github.com/advisories/GHSA-8g38-3m6v-232jghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2024-27097ghsaADVISORY
- docs.ckan.org/en/2.10/changelog.htmlghsaWEB
- github.com/ckan/ckan/commit/5fa133e7e9019573066455b5d442e93c62b3fc93ghsaWEB
- github.com/ckan/ckan/commit/81b56c55e5e3651d7fcf9642cd5a489a9b62212cghsax_refsource_MISCWEB
- github.com/ckan/ckan/commit/d81f411bff2da7347c343a83e17f5814475b5b64ghsaWEB
- github.com/ckan/ckan/security/advisories/GHSA-8g38-3m6v-232jghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.