Skip to content

Commit a86519e

Browse files
authored
Merge pull request #1207 from sophieliu15/fix-issue-511043249
Fix Stackdriver Filter Injection vulnerability for In/NotIn operators
2 parents b6f2c40 + ab25963 commit a86519e

2 files changed

Lines changed: 40 additions & 2 deletions

File tree

custom-metrics-stackdriver-adapter/pkg/adapter/translator/query_builder.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -741,7 +741,7 @@ func (t *Translator) filterForSelector(metricSelector labels.Selector, allowedLa
741741
case selection.In:
742742
if isAllowedLabelName(req.Key(), allowedLabelPrefixes, allowedFullLabelNames) {
743743
if len(l) == 1 {
744-
filters = append(filters, fmt.Sprintf("%s = %s", req.Key(), l[0]))
744+
filters = append(filters, fmt.Sprintf("%s = %q", req.Key(), l[0]))
745745
} else {
746746
filters = append(filters, fmt.Sprintf("%s = one_of(%s)", req.Key(), strings.Join(quoteAll(l), ",")))
747747
}
@@ -751,7 +751,7 @@ func (t *Translator) filterForSelector(metricSelector labels.Selector, allowedLa
751751
case selection.NotIn:
752752
if isAllowedLabelName(req.Key(), allowedLabelPrefixes, allowedFullLabelNames) {
753753
if len(l) == 1 {
754-
filters = append(filters, fmt.Sprintf("%s != %s", req.Key(), l[0]))
754+
filters = append(filters, fmt.Sprintf("%s != %q", req.Key(), l[0]))
755755
} else {
756756
filters = append(filters, fmt.Sprintf("NOT %s = one_of(%s)", req.Key(), strings.Join(quoteAll(l), ",")))
757757
}

custom-metrics-stackdriver-adapter/pkg/adapter/translator/query_builder_test.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1585,3 +1585,41 @@ func TestTranslator_GetMetricKind_CacheKeyIsolation(t *testing.T) {
15851585
t.Errorf("metricKindCache.get(%v) = true, want false", keyDefault)
15861586
}
15871587
}
1588+
1589+
func TestTranslator_QueryBuilder_FilterInjection_Prevention(t *testing.T) {
1590+
translator, _ :=
1591+
NewFakeTranslator(2*time.Minute, time.Minute, "my-project", "my-cluster", "my-zone", time.Date(2017, 1, 2, 13, 2, 0, 0, time.UTC), true)
1592+
1593+
allowedLabelPrefixes := []string{"metric.labels"}
1594+
allowedFullLabelNames := []string{}
1595+
1596+
// 1. Test 'In' operator with single unquoted element containing injection payload.
1597+
reqIn, err := labels.NewRequirement("metric.labels.custom", selection.In, []string{"safedummy"})
1598+
if err != nil {
1599+
t.Fatalf("Failed to create requirement: %v", err)
1600+
}
1601+
selectorIn := labels.NewSelector().Add(*reqIn)
1602+
filterIn, _, err := translator.filterForSelector(selectorIn, allowedLabelPrefixes, allowedFullLabelNames)
1603+
if err != nil {
1604+
t.Fatalf("Failed to build filter: %v", err)
1605+
}
1606+
expectedFilterIn := "metric.labels.custom = \"safedummy\""
1607+
if filterIn != expectedFilterIn {
1608+
t.Errorf("Expected filter: %s, got: %s", expectedFilterIn, filterIn)
1609+
}
1610+
1611+
// 2. Test 'NotIn' operator with single unquoted element.
1612+
reqNotIn, err := labels.NewRequirement("metric.labels.custom", selection.NotIn, []string{"safedummy"})
1613+
if err != nil {
1614+
t.Fatalf("Failed to create requirement: %v", err)
1615+
}
1616+
selectorNotIn := labels.NewSelector().Add(*reqNotIn)
1617+
filterNotIn, _, err := translator.filterForSelector(selectorNotIn, allowedLabelPrefixes, allowedFullLabelNames)
1618+
if err != nil {
1619+
t.Fatalf("Failed to build filter: %v", err)
1620+
}
1621+
expectedFilterNotIn := "metric.labels.custom != \"safedummy\""
1622+
if filterNotIn != expectedFilterNotIn {
1623+
t.Errorf("Expected filter: %s, got: %s", expectedFilterNotIn, filterNotIn)
1624+
}
1625+
}

0 commit comments

Comments
 (0)