Skip to content

Commit b2c241c

Browse files
committed
ECOPROJECT-4724 | fix: Escape SQL string fields in query builder to prevent second-order SQL injection
Cluster names from user-uploaded RVTools spreadsheets were interpolated unescaped into ~27 DuckDB query templates via text/template, allowing single-quote breakout and arbitrary SQL execution (e.g. read_text() for file exfiltration). Apply escapeSQLString() to all user-controlled queryParams fields (ClusterFilter, OSFilter, PowerStateFilter, VmIDFilter, Category) before template execution. Signed-off-by: Aviel Segev <asegev@redhat.com>
1 parent db4c785 commit b2c241c

1 file changed

Lines changed: 32 additions & 32 deletions

File tree

pkg/duckdb_parser/builder.go

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,10 @@ func (b *QueryBuilder) VMQuery(filters Filters, options Options) (string, error)
8585

8686
params := queryParams{
8787
NetworkColumns: networkColumns,
88-
ClusterFilter: filters.Cluster,
89-
OSFilter: filters.OS,
90-
PowerStateFilter: filters.PowerState,
91-
VmIDFilter: filters.VmId,
88+
ClusterFilter: escapeSQLString(filters.Cluster),
89+
OSFilter: escapeSQLString(filters.OS),
90+
PowerStateFilter: escapeSQLString(filters.PowerState),
91+
VmIDFilter: escapeSQLString(filters.VmId),
9292
VMListFilter: buildVMListFilter(filters.VMList, "i"),
9393
Limit: options.Limit,
9494
Offset: options.Offset,
@@ -99,7 +99,7 @@ func (b *QueryBuilder) VMQuery(filters Filters, options Options) (string, error)
9999
// DatastoreQuery builds the datastore query with filters and pagination.
100100
func (b *QueryBuilder) DatastoreQuery(filters Filters, options Options) (string, error) {
101101
params := queryParams{
102-
ClusterFilter: filters.Cluster,
102+
ClusterFilter: escapeSQLString(filters.Cluster),
103103
Limit: options.Limit,
104104
Offset: options.Offset,
105105
}
@@ -109,7 +109,7 @@ func (b *QueryBuilder) DatastoreQuery(filters Filters, options Options) (string,
109109
// NetworkQuery builds the network query with filters and pagination.
110110
func (b *QueryBuilder) NetworkQuery(filters Filters, options Options) (string, error) {
111111
params := queryParams{
112-
ClusterFilter: filters.Cluster,
112+
ClusterFilter: escapeSQLString(filters.Cluster),
113113
Limit: options.Limit,
114114
Offset: options.Offset,
115115
}
@@ -119,7 +119,7 @@ func (b *QueryBuilder) NetworkQuery(filters Filters, options Options) (string, e
119119
// HostQuery builds the host query with filters and pagination.
120120
func (b *QueryBuilder) HostQuery(filters Filters, options Options) (string, error) {
121121
params := queryParams{
122-
ClusterFilter: filters.Cluster,
122+
ClusterFilter: escapeSQLString(filters.Cluster),
123123
Limit: options.Limit,
124124
Offset: options.Offset,
125125
}
@@ -129,7 +129,7 @@ func (b *QueryBuilder) HostQuery(filters Filters, options Options) (string, erro
129129
// OsQuery builds the OS summary query with filters.
130130
func (b *QueryBuilder) OsQuery(filters Filters) (string, error) {
131131
params := queryParams{
132-
ClusterFilter: filters.Cluster,
132+
ClusterFilter: escapeSQLString(filters.Cluster),
133133
VMListFilter: buildVMListFilter(filters.VMList, "v"),
134134
}
135135
return b.buildQuery("os_query", mustGetTemplate("os_query"), params)
@@ -159,8 +159,8 @@ func (b *QueryBuilder) ClusterFeaturesQuery(clusterName string) (string, error)
159159
// VMCountQuery builds the VM count query with filters.
160160
func (b *QueryBuilder) VMCountQuery(filters Filters) (string, error) {
161161
params := queryParams{
162-
ClusterFilter: filters.Cluster,
163-
PowerStateFilter: filters.PowerState,
162+
ClusterFilter: escapeSQLString(filters.Cluster),
163+
PowerStateFilter: escapeSQLString(filters.PowerState),
164164
VMListFilter: buildVMListFilter(filters.VMList, ""),
165165
}
166166
return b.buildQuery("vm_count_query", mustGetTemplate("vm_count_query"), params)
@@ -169,7 +169,7 @@ func (b *QueryBuilder) VMCountQuery(filters Filters) (string, error) {
169169
// PowerStateCountsQuery builds the power state counts query.
170170
func (b *QueryBuilder) PowerStateCountsQuery(filters Filters) (string, error) {
171171
params := queryParams{
172-
ClusterFilter: filters.Cluster,
172+
ClusterFilter: escapeSQLString(filters.Cluster),
173173
VMListFilter: buildVMListFilter(filters.VMList, ""),
174174
}
175175
return b.buildQuery("power_state_counts_query", mustGetTemplate("power_state_counts_query"), params)
@@ -178,15 +178,15 @@ func (b *QueryBuilder) PowerStateCountsQuery(filters Filters) (string, error) {
178178
// HostPowerStateCountsQuery builds the host power state counts query.
179179
func (b *QueryBuilder) HostPowerStateCountsQuery(filters Filters) (string, error) {
180180
params := queryParams{
181-
ClusterFilter: filters.Cluster,
181+
ClusterFilter: escapeSQLString(filters.Cluster),
182182
}
183183
return b.buildQuery("host_power_state_counts_query", mustGetTemplate("host_power_state_counts_query"), params)
184184
}
185185

186186
// CPUTierQuery builds the CPU tier distribution query.
187187
func (b *QueryBuilder) CPUTierQuery(filters Filters) (string, error) {
188188
params := queryParams{
189-
ClusterFilter: filters.Cluster,
189+
ClusterFilter: escapeSQLString(filters.Cluster),
190190
VMListFilter: buildVMListFilter(filters.VMList, ""),
191191
}
192192
return b.buildQuery("cpu_tier_query", mustGetTemplate("cpu_tier_query"), params)
@@ -195,7 +195,7 @@ func (b *QueryBuilder) CPUTierQuery(filters Filters) (string, error) {
195195
// MemoryTierQuery builds the memory tier distribution query.
196196
func (b *QueryBuilder) MemoryTierQuery(filters Filters) (string, error) {
197197
params := queryParams{
198-
ClusterFilter: filters.Cluster,
198+
ClusterFilter: escapeSQLString(filters.Cluster),
199199
VMListFilter: buildVMListFilter(filters.VMList, ""),
200200
}
201201
return b.buildQuery("memory_tier_query", mustGetTemplate("memory_tier_query"), params)
@@ -204,7 +204,7 @@ func (b *QueryBuilder) MemoryTierQuery(filters Filters) (string, error) {
204204
// NicTierQuery builds the NIC count tier distribution query.
205205
func (b *QueryBuilder) NicTierQuery(filters Filters) (string, error) {
206206
params := queryParams{
207-
ClusterFilter: filters.Cluster,
207+
ClusterFilter: escapeSQLString(filters.Cluster),
208208
VMListFilter: buildVMListFilter(filters.VMList, "i"),
209209
}
210210
return b.buildQuery("nic_tier_query", mustGetTemplate("nic_tier_query"), params)
@@ -213,7 +213,7 @@ func (b *QueryBuilder) NicTierQuery(filters Filters) (string, error) {
213213
// ComplexityDistributionQuery builds the complexity distribution query.
214214
func (b *QueryBuilder) ComplexityDistributionQuery(filters Filters) (string, error) {
215215
params := queryParams{
216-
ClusterFilter: filters.Cluster,
216+
ClusterFilter: escapeSQLString(filters.Cluster),
217217
VMListFilter: buildVMListFilter(filters.VMList, "i"),
218218
}
219219
return b.buildQuery("complexity_distribution_query", mustGetTemplate("complexity_distribution_query"), params)
@@ -222,7 +222,7 @@ func (b *QueryBuilder) ComplexityDistributionQuery(filters Filters) (string, err
222222
// DiskSizeTierQuery builds the disk size tier distribution query.
223223
func (b *QueryBuilder) DiskSizeTierQuery(filters Filters) (string, error) {
224224
params := queryParams{
225-
ClusterFilter: filters.Cluster,
225+
ClusterFilter: escapeSQLString(filters.Cluster),
226226
VMListFilter: buildVMListFilter(filters.VMList, "i"),
227227
}
228228
return b.buildQuery("disk_size_tier_query", mustGetTemplate("disk_size_tier_query"), params)
@@ -231,7 +231,7 @@ func (b *QueryBuilder) DiskSizeTierQuery(filters Filters) (string, error) {
231231
// DiskComplexityTierQuery builds the disk complexity tier distribution query.
232232
func (b *QueryBuilder) DiskComplexityTierQuery(filters Filters) (string, error) {
233233
params := queryParams{
234-
ClusterFilter: filters.Cluster,
234+
ClusterFilter: escapeSQLString(filters.Cluster),
235235
VMListFilter: buildVMListFilter(filters.VMList, "i"),
236236
}
237237
return b.buildQuery("disk_complexity_tier_query", mustGetTemplate("disk_complexity_tier_query"), params)
@@ -240,7 +240,7 @@ func (b *QueryBuilder) DiskComplexityTierQuery(filters Filters) (string, error)
240240
// DiskTypeSummaryQuery builds the disk type summary query.
241241
func (b *QueryBuilder) DiskTypeSummaryQuery(filters Filters) (string, error) {
242242
params := queryParams{
243-
ClusterFilter: filters.Cluster,
243+
ClusterFilter: escapeSQLString(filters.Cluster),
244244
VMListFilter: buildVMListFilter(filters.VMList, ""),
245245
}
246246
return b.buildQuery("disk_type_summary_query", mustGetTemplate("disk_type_summary_query"), params)
@@ -249,7 +249,7 @@ func (b *QueryBuilder) DiskTypeSummaryQuery(filters Filters) (string, error) {
249249
// ResourceTotalsQuery builds the resource totals query.
250250
func (b *QueryBuilder) ResourceTotalsQuery(filters Filters) (string, error) {
251251
params := queryParams{
252-
ClusterFilter: filters.Cluster,
252+
ClusterFilter: escapeSQLString(filters.Cluster),
253253
VMListFilter: buildVMListFilter(filters.VMList, "i"),
254254
}
255255
return b.buildQuery("resource_totals_query", mustGetTemplate("resource_totals_query"), params)
@@ -258,7 +258,7 @@ func (b *QueryBuilder) ResourceTotalsQuery(filters Filters) (string, error) {
258258
// AllocatedVCPUsQuery builds the allocated vCPUs query.
259259
func (b *QueryBuilder) AllocatedVCPUsQuery(filters Filters) (string, error) {
260260
params := queryParams{
261-
ClusterFilter: filters.Cluster,
261+
ClusterFilter: escapeSQLString(filters.Cluster),
262262
VMListFilter: buildVMListFilter(filters.VMList, ""),
263263
}
264264
return b.buildQuery("allocated_vcpus_query", mustGetTemplate("allocated_vcpus_query"), params)
@@ -267,7 +267,7 @@ func (b *QueryBuilder) AllocatedVCPUsQuery(filters Filters) (string, error) {
267267
// AllocatedMemoryQuery builds the allocated memory query.
268268
func (b *QueryBuilder) AllocatedMemoryQuery(filters Filters) (string, error) {
269269
params := queryParams{
270-
ClusterFilter: filters.Cluster,
270+
ClusterFilter: escapeSQLString(filters.Cluster),
271271
VMListFilter: buildVMListFilter(filters.VMList, ""),
272272
}
273273
return b.buildQuery("allocated_memory_query", mustGetTemplate("allocated_memory_query"), params)
@@ -276,23 +276,23 @@ func (b *QueryBuilder) AllocatedMemoryQuery(filters Filters) (string, error) {
276276
// TotalHostCPUsQuery builds the total host CPUs query.
277277
func (b *QueryBuilder) TotalHostCPUsQuery(filters Filters) (string, error) {
278278
params := queryParams{
279-
ClusterFilter: filters.Cluster,
279+
ClusterFilter: escapeSQLString(filters.Cluster),
280280
}
281281
return b.buildQuery("total_host_cpus_query", mustGetTemplate("total_host_cpus_query"), params)
282282
}
283283

284284
// TotalHostMemoryQuery builds the total host memory query.
285285
func (b *QueryBuilder) TotalHostMemoryQuery(filters Filters) (string, error) {
286286
params := queryParams{
287-
ClusterFilter: filters.Cluster,
287+
ClusterFilter: escapeSQLString(filters.Cluster),
288288
}
289289
return b.buildQuery("total_host_memory_query", mustGetTemplate("total_host_memory_query"), params)
290290
}
291291

292292
// VMCountByNetworkQuery builds the VM count by network query.
293293
func (b *QueryBuilder) VMCountByNetworkQuery(filters Filters) (string, error) {
294294
params := queryParams{
295-
ClusterFilter: filters.Cluster,
295+
ClusterFilter: escapeSQLString(filters.Cluster),
296296
VMListFilter: buildVMListFilter(filters.VMList, "i"),
297297
}
298298
return b.buildQuery("vm_count_by_network_query", mustGetTemplate("vm_count_by_network_query"), params)
@@ -311,7 +311,7 @@ func (b *QueryBuilder) ClustersPerDatacenterQuery() (string, error) {
311311
// MigratableCountQuery builds the migratable VMs count query.
312312
func (b *QueryBuilder) MigratableCountQuery(filters Filters) (string, error) {
313313
params := queryParams{
314-
ClusterFilter: filters.Cluster,
314+
ClusterFilter: escapeSQLString(filters.Cluster),
315315
VMListFilter: buildVMListFilter(filters.VMList, "i"),
316316
}
317317
return b.buildQuery("migratable_count_query", mustGetTemplate("migratable_count_query"), params)
@@ -320,7 +320,7 @@ func (b *QueryBuilder) MigratableCountQuery(filters Filters) (string, error) {
320320
// MigratableWithWarningsCountQuery builds the migratable with warnings count query.
321321
func (b *QueryBuilder) MigratableWithWarningsCountQuery(filters Filters) (string, error) {
322322
params := queryParams{
323-
ClusterFilter: filters.Cluster,
323+
ClusterFilter: escapeSQLString(filters.Cluster),
324324
VMListFilter: buildVMListFilter(filters.VMList, "i"),
325325
}
326326
return b.buildQuery("migratable_with_warnings_count_query", mustGetTemplate("migratable_with_warnings_count_query"), params)
@@ -329,7 +329,7 @@ func (b *QueryBuilder) MigratableWithWarningsCountQuery(filters Filters) (string
329329
// NotMigratableCountQuery builds the not migratable VMs count query.
330330
func (b *QueryBuilder) NotMigratableCountQuery(filters Filters) (string, error) {
331331
params := queryParams{
332-
ClusterFilter: filters.Cluster,
332+
ClusterFilter: escapeSQLString(filters.Cluster),
333333
VMListFilter: buildVMListFilter(filters.VMList, "i"),
334334
}
335335
return b.buildQuery("not_migratable_count_query", mustGetTemplate("not_migratable_count_query"), params)
@@ -338,8 +338,8 @@ func (b *QueryBuilder) NotMigratableCountQuery(filters Filters) (string, error)
338338
// MigrationIssuesQuery builds the migration issues query.
339339
func (b *QueryBuilder) MigrationIssuesQuery(filters Filters, category string) (string, error) {
340340
params := queryParams{
341-
ClusterFilter: filters.Cluster,
342-
Category: category,
341+
ClusterFilter: escapeSQLString(filters.Cluster),
342+
Category: escapeSQLString(category),
343343
VMListFilter: buildVMListFilter(filters.VMList, "i"),
344344
}
345345
return b.buildQuery("migration_issues_query", mustGetTemplate("migration_issues_query"), params)
@@ -348,7 +348,7 @@ func (b *QueryBuilder) MigrationIssuesQuery(filters Filters, category string) (s
348348
// ResourceBreakdownsQuery builds the resource breakdowns query.
349349
func (b *QueryBuilder) ResourceBreakdownsQuery(filters Filters) (string, error) {
350350
params := queryParams{
351-
ClusterFilter: filters.Cluster,
351+
ClusterFilter: escapeSQLString(filters.Cluster),
352352
VMListFilter: buildVMListFilter(filters.VMList, "i"),
353353
}
354354
return b.buildQuery("resource_breakdowns_query", mustGetTemplate("resource_breakdowns_query"), params)
@@ -362,7 +362,7 @@ func (b *QueryBuilder) AboutQuery() (string, error) {
362362
// VMsWithSharedDisksCountQuery builds the VMs with shared disks count query.
363363
func (b *QueryBuilder) VMsWithSharedDisksCountQuery(filters Filters) (string, error) {
364364
params := queryParams{
365-
ClusterFilter: filters.Cluster,
365+
ClusterFilter: escapeSQLString(filters.Cluster),
366366
VMListFilter: buildVMListFilter(filters.VMList, "i"),
367367
}
368368
return b.buildQuery("vms_with_shared_disks_count_query", mustGetTemplate("vms_with_shared_disks_count_query"), params)

0 commit comments

Comments
 (0)