Menu ▾ ▴

#26 [Security/Low] D365 OData $filter built via unescaped string interpolation

closed
nobody
None
2026-06-13
2026-06-12
Anonymous
No

Originally created by: pyy3

Severity: Low–Medium · Type: security / robustness

Summary

The D365 incremental sync builds the OData $filter by interpolating the cursor value directly into the query string with no quoting/escaping or type validation.

Location

source-d365-fno/source_d365_fno/streams.py (~line 157):

cursor_value = (stream_state or {}).get(self.cursor_field)
if cursor_value and params:
    params["$filter"] = f"{self.cursor_field} ge {cursor_value}"

Impact

The cursor originates from D365-returned data / persisted Airbyte state rather than direct end-user input, so this is primarily a robustness + tampering concern rather than open injection:

  • A string-typed cursor would need OData quoting ('...') and would otherwise produce a malformed filter.
  • A tampered state store could inject OData filter syntax to alter query semantics.

Suggested fix

  • Validate cursor_value type before use (expect ISO datetime / known type); reject otherwise.
  • Quote/encode per the OData type (datetimes unquoted, strings single-quoted with escaping).
  • Consider building params via the Airbyte CDK request-params mechanism rather than raw f-strings.

Related

Tickets: #34

Discussion

  • Anonymous

    Anonymous - 2026-06-13

    Ticket changed by: pyy3

    • status: open --> closed
     
  • Anonymous

    Anonymous - 2026-06-13

    Originally posted by: pyy3

    Fixed in [#34] (merged to main).

     

    Related

    Tickets: #34


Log in to post a comment.