@@ -1889,7 +1889,7 @@ int cbm_store_search(cbm_store_t *s, const cbm_search_params_t *params, cbm_sear
18891889 BIND_TEXT (like_pattern );
18901890 }
18911891
1892- /* Exclude labels: add NOT IN clause directly (no bind params — values are code-provided) */
1892+ /* Exclude labels: use parameterized placeholders to prevent SQL injection */
18931893 if (params -> exclude_labels ) {
18941894 char excl_clause [512 ] = "n.label NOT IN (" ;
18951895 int elen = (int )strlen (excl_clause );
@@ -1900,11 +1900,12 @@ int cbm_store_search(cbm_store_t *s, const cbm_search_params_t *params, cbm_sear
19001900 elen = (int )sizeof (excl_clause ) - 1 ;
19011901 }
19021902 }
1903- elen += snprintf (excl_clause + elen , sizeof (excl_clause ) - (size_t )elen , "'%s' " ,
1904- params -> exclude_labels [ i ] );
1903+ elen += snprintf (excl_clause + elen , sizeof (excl_clause ) - (size_t )elen , "?%d " ,
1904+ bind_idx + 1 );
19051905 if (elen >= (int )sizeof (excl_clause )) {
19061906 elen = (int )sizeof (excl_clause ) - 1 ;
19071907 }
1908+ BIND_TEXT (params -> exclude_labels [i ]);
19081909 }
19091910 snprintf (excl_clause + elen , sizeof (excl_clause ) - (size_t )elen , ")" );
19101911 ADD_WHERE (excl_clause );
@@ -2040,8 +2041,9 @@ int cbm_store_bfs(cbm_store_t *s, int64_t start_id, const char *direction, const
20402041 }
20412042 out -> root = root ;
20422043
2043- /* Build edge type IN clause */
2044- char types_clause [512 ] = "'CALLS'" ;
2044+ /* Build edge type IN clause with parameterized placeholders */
2045+ char types_clause [512 ] = "?1" ;
2046+ const char * default_edge_type = "CALLS" ;
20452047 if (edge_type_count > 0 ) {
20462048 int tlen = 0 ;
20472049 for (int i = 0 ; i < edge_type_count ; i ++ ) {
@@ -2051,8 +2053,8 @@ int cbm_store_bfs(cbm_store_t *s, int64_t start_id, const char *direction, const
20512053 tlen = (int )sizeof (types_clause ) - 1 ;
20522054 }
20532055 }
2054- tlen += snprintf (types_clause + tlen , sizeof (types_clause ) - (size_t )tlen , "'%s' " ,
2055- edge_types [ i ] );
2056+ tlen += snprintf (types_clause + tlen , sizeof (types_clause ) - (size_t )tlen , "?%d " ,
2057+ i + 1 );
20562058 if (tlen >= (int )sizeof (types_clause )) {
20572059 tlen = (int )sizeof (types_clause ) - 1 ;
20582060 }
@@ -2099,6 +2101,15 @@ int cbm_store_bfs(cbm_store_t *s, int64_t start_id, const char *direction, const
20992101 return CBM_STORE_ERR ;
21002102 }
21012103
2104+ /* Bind edge type parameters */
2105+ if (edge_type_count > 0 ) {
2106+ for (int i = 0 ; i < edge_type_count ; i ++ ) {
2107+ bind_text (stmt , i + 1 , edge_types [i ]);
2108+ }
2109+ } else {
2110+ bind_text (stmt , 1 , default_edge_type );
2111+ }
2112+
21022113 int cap = 16 ;
21032114 int n = 0 ;
21042115 cbm_node_hop_t * visited = malloc (cap * sizeof (cbm_node_hop_t ));
@@ -2147,6 +2158,15 @@ int cbm_store_bfs(cbm_store_t *s, int64_t start_id, const char *direction, const
21472158 sqlite3_stmt * estmt = NULL ;
21482159 rc = sqlite3_prepare_v2 (s -> db , edge_sql , -1 , & estmt , NULL );
21492160 if (rc == SQLITE_OK ) {
2161+ /* Bind edge type parameters for the edge query */
2162+ if (edge_type_count > 0 ) {
2163+ for (int i = 0 ; i < edge_type_count ; i ++ ) {
2164+ bind_text (estmt , i + 1 , edge_types [i ]);
2165+ }
2166+ } else {
2167+ bind_text (estmt , 1 , default_edge_type );
2168+ }
2169+
21502170 int ecap = 8 ;
21512171 int en = 0 ;
21522172 cbm_edge_info_t * edges = malloc (ecap * sizeof (cbm_edge_info_t ));
0 commit comments