Skip to content

fix: [cof2misp] fix operator precedence in COF timestamp validation - #894

Open
elhoim wants to merge 1 commit into
MISP:mainfrom
elhoim:fix/086-cof-precedence
Open

fix: [cof2misp] fix operator precedence in COF timestamp validation#894
elhoim wants to merge 1 commit into
MISP:mainfrom
elhoim:fix/086-cof-precedence

Conversation

@elhoim

@elhoim elhoim commented Aug 31, 2026

Copy link
Copy Markdown
Member

The defect

In misp_modules/lib/cof2misp/cof.py, is_cof_valid_simple() checked for the presence of a valid timestamp pair like this:

if not ("time_first" in d and "time_last" in d) or ("zone_time_first" in d and "zone_time_last" in d):

Due to Python operator precedence, not binds tighter than or, so this parses as:

(not ("time_first" in d and "time_last" in d)) or ("zone_time_first" in d and "zone_time_last" in d)

The intent was "reject the record unless it has EITHER the time_first/time_last pair OR the zone_time_first/zone_time_last pair" — i.e. not (A or B). Instead, the expression evaluates to (not A) or B, which is true (and so returns False, rejecting the record) whenever A is false, regardless of B. Concretely: a record that has only zone_time_first/zone_time_last (and lacks time_first/time_last) makes A false, so not A is True, and the whole condition is True — the record is wrongly rejected as missing required fields, even though it actually has a valid timestamp pair.

Impact

Any COF (Common Output Format) DNS record that carries only the zone_time_first/zone_time_last fields — a legitimate, documented alternative to time_first/time_last — is silently dropped by the cof2misp conversion before it ever reaches MISP. An analyst importing passive DNS data in this format loses valid records without any indication that they were rejected, other than a generic stderr message that (incorrectly) claims required fields are missing.

The fix

Add the missing parentheses so the or combines the two "has a valid pair" checks before negation, matching the intended not (A or B) semantics:

if not (("time_first" in d and "time_last" in d) or ("zone_time_first" in d and "zone_time_last" in d)):

No behaviour change beyond correcting this logic error to match the documented/intended validation rule.

Verification

  • python -m py_compile misp_modules/lib/cof2misp/cof.py — clean.
  • Full module test suite: 161 passed, 4 skipped, 5 subtests passed in 22.08s.

Found during a review of the repository; other findings are being submitted as separate PRs.

🤖 Generated with Claude Code

https://claude.ai/code/session_018dfYpyaSZd1nxSRLr8suj8

is_cof_valid_simple checked `not (A and B) or (C and D)`, which Python
parses as `(not (A and B)) or (C and D)` rather than the intended
`not ((A and B) or (C and D))`. As a result, a record carrying only the
valid zone_time_first/zone_time_last pair (and no time_first/time_last)
was rejected as invalid, since `not (A and B)` is already True in that
case and short-circuits the OR to True, triggering the "missing
mandatory fields" error and a False return even though the record is
well-formed. A record with both pairs present was also flagged wrong
for the same reason.

Parenthesised the check as `not ((A and B) or (C and D))` so validation
succeeds whenever either timestamp pair is present, matching the
intended COF semantics.

Verified with py_compile and the full pytest suite against a live
modules server on port 6786: 161 passed, 4 skipped, 5 subtests passed,
matching the documented baseline.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018dfYpyaSZd1nxSRLr8suj8
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.

1 participant