fix(event-publisher): sanitise untrusted values before logging - #67
Merged
Conversation
CodeQL alert py/log-injection (CWE-117) flagged the `key: %s` log call,
which is built from the sub_service, sub_service_group and geohash path
parameters. Those three are already allowlist-validated before the log
call, so that specific line was not exploitable -- CodeQL simply does not
model regex-match guards as taint barriers.
Auditing the alert turned up a genuine instance the scan missed three
lines below: the asn1tools EncodeError message embeds field names and
values taken from the request JSON body, which is only checked for being
a dict. That message can carry raw CR/LF. Verified end to end against a
real ASN.1 encoder -- POSTing {"header": "x\r\n<fake log line>"} to the
unpatched service writes a fully-formed forged CRITICAL entry to app.log
that is indistinguishable from a genuine one.
Add a sanitize_for_log() helper that strips C0/C1 control characters and
DEL, and truncates to a bounded length so a large payload cannot flood
the log. Apply it at both user-derived sinks. The trailing replace()
calls are redundant with the regex, but they are the pattern CodeQL
recognises as a taint barrier; a comment marks them as load-bearing.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Luis Alfredo Perez Medina <perezmlal@outlook.com>
perezmlal
force-pushed
the
fix/log-injection-event-publisher
branch
from
August 10, 2026 21:26
3034197 to
abb4f60
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes CodeQL alert #3 —
py/log-injection(CWE-117).The flagged line was already safe
The alert points at
app.logger.info("key: %s", key), wherekeyis built from thesub_service,sub_service_groupandgeohashpath parameters. All three are allowlist-validated a few lines earlier:GEOHASH_REandSUB_SERVICE_GROUP_REcannot match CR or LF, andsub_servicemust pass a set-membership check. CodeQL does not model regex-match guards as taint barriers, so it reports the flow regardless.The scan missed a real one three lines below
app.logger.warning("Encoding failed: %s", exc)logs theasn1toolsEncodeErrormessage, which embeds field names and values taken from the request JSON body. That body is only checked for being adict— its contents are never validated, and the error message can carry raw CR/LF.Verified end-to-end against a real ASN.1 encoder. Against the unpatched service:
app.loggains a fully-formed forged entry, indistinguishable from a genuine one:With the fix, the same request stays on one line:
Changes
sanitize_for_log()inEventPublisher.py: strips C0/C1 control characters and DEL, and truncates toLOG_VALUE_MAX_LENGTH(default 256, overridable viaconfig, following the existinggetattr(config, ...)pattern) so a large payload cannot flood the log.hexlifyoutput.EncodeErrorpath and asserts the emitted record contains no line break.CHANGELOG.mdentry underUnreleased → Security.Note for reviewers
The trailing
.replace("\r", "").replace("\n", "")is redundant with the regex that precedes it. It is deliberate and load-bearing: it is the sanitisation pattern CodeQL'spy/log-injectionquery recognises as a taint barrier. Removing it as a simplification reopens the alert. There is a comment saying so at the call site.Verification
pytest --cov-fail-under=80ruff checkbandit -rAlert closure is confirmed by this PR's
Analyze (python)run, since no CodeQL CLI is available locally.