fix: threats sequence-pair binds type/json-filter as ? params (P1 #23)
ober
97265347ed513ae99ffe5b7b79a79e65e9123786
--- a/jsecmon/threats.ss +++ b/jsecmon/threats.ss @@ -227,17 +227,28 @@ ;; Generic: event_type A (optional json equality on data) followed by event_type ;; B within window_ms on the same host. json-filter is (path . literal), e.g. - ;; ("$.success" . "1") -> AND json_extract(data,'$.success')=1. + ;; ("$.success" . "1") -> AND json_extract(data,'$.success')=1. type-a/type-b + ;; and the json-filter path+value are bound as ? params (never interpolated), + ;; so a value that reaches this helper can't inject SQL. Numeric literals stay + ;; numeric so `= ?` keeps the original `=1` integer match against json_extract. + (def (json-literal v) + (if (string? v) (or (string->number v) v) v)) (def (sequence-pair db type-a json-filter type-b window-ms rule-name severity filter) - (let ((as (filtered-query db - (str "SELECT host, timestamp_ms FROM events WHERE event_type='" type-a "'" - (if json-filter - (str " AND json_extract(data,'" (car json-filter) "')=" (cdr json-filter)) - "")) - " ORDER BY host, timestamp_ms" filter)) - (bs (filtered-query db - (str "SELECT host, timestamp_ms FROM events WHERE event_type='" type-b "'") - " ORDER BY host, timestamp_ms" filter))) + (let* ((a-binds (if json-filter + (list type-a (car json-filter) (json-literal (cdr json-filter))) + (list type-a))) + (aw (build-where filter (+ 1 (length a-binds)))) + (as (apply sqlite-query db + (str (if json-filter + "SELECT host, timestamp_ms FROM events WHERE event_type = ?1 AND json_extract(data, ?2) = ?3" + "SELECT host, timestamp_ms FROM events WHERE event_type = ?1") + (car aw) " ORDER BY host, timestamp_ms") + (append a-binds (cdr aw)))) + (bw (build-where filter 2)) + (bs (apply sqlite-query db + (str "SELECT host, timestamp_ms FROM events WHERE event_type = ?1" + (car bw) " ORDER BY host, timestamp_ms") + (cons type-b (cdr bw))))) (pair-sequence as bs window-ms (lambda (a b) (make-anomaly rule-name (a-str a "host") severity (a-num a "timestamp_ms")