Skip to content

Commit d56c6f4

Browse files
authored
Merge pull request #1038 from cappyzawa/validate-proxy-url
runtime/secrets: validate proxy URL scheme and length
2 parents ca99961 + 3e994a9 commit d56c6f4

File tree

3 files changed

+44
-3
lines changed

3 files changed

+44
-3
lines changed

runtime/secrets/converter.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,23 +133,34 @@ func TLSConfigFromSecret(ctx context.Context, secret *corev1.Secret, opts ...TLS
133133
// proxy URL. Optional "username" and "password" fields can be provided
134134
// for proxy authentication.
135135
func ProxyURLFromSecret(ctx context.Context, secret *corev1.Secret) (*url.URL, error) {
136+
ref := client.ObjectKeyFromObject(secret)
137+
136138
addressData, exists := secret.Data[KeyAddress]
137139
if !exists {
138140
return nil, &KeyNotFoundError{Key: KeyAddress, Secret: secret}
139141
}
140142

141143
address := string(addressData)
142144
if address == "" {
143-
ref := client.ObjectKeyFromObject(secret)
144145
return nil, fmt.Errorf("secret '%s': proxy address is empty", ref)
145146
}
146147

148+
// Validate length before parsing to avoid parsing large invalid URLs.
149+
// The 2048 character limit matches the validation used in notification-controller's
150+
// spec.address field.
151+
if len(address) > 2048 {
152+
return nil, fmt.Errorf("secret '%s': proxy URL exceeds maximum length of 2048 characters", ref)
153+
}
154+
147155
proxyURL, err := url.Parse(address)
148156
if err != nil {
149-
ref := client.ObjectKeyFromObject(secret)
150157
return nil, fmt.Errorf("secret '%s': failed to parse proxy address '%s': %w", ref, address, err)
151158
}
152159

160+
if proxyURL.Scheme != "http" && proxyURL.Scheme != "https" {
161+
return nil, fmt.Errorf("secret '%s': proxy URL must use http or https scheme, got '%s'", ref, proxyURL.Scheme)
162+
}
163+
153164
username, hasUsername := secret.Data[KeyUsername]
154165
password, hasPassword := secret.Data[KeyPassword]
155166

runtime/secrets/converter_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -752,6 +752,36 @@ func TestProxyURLFromSecret(t *testing.T) {
752752
),
753753
errMsg: "secret 'default/proxy-secret': failed to parse proxy address",
754754
},
755+
{
756+
name: "invalid scheme - ftp",
757+
secret: testSecret(
758+
withName("proxy-secret"),
759+
withData(map[string][]byte{
760+
secrets.KeyAddress: []byte("ftp://ftp.example.com:21"),
761+
}),
762+
),
763+
errMsg: "secret 'default/proxy-secret': proxy URL must use http or https scheme, got 'ftp'",
764+
},
765+
{
766+
name: "invalid scheme - no scheme",
767+
secret: testSecret(
768+
withName("proxy-secret"),
769+
withData(map[string][]byte{
770+
secrets.KeyAddress: []byte("proxy.example.com:8080"),
771+
}),
772+
),
773+
errMsg: "secret 'default/proxy-secret': proxy URL must use http or https scheme",
774+
},
775+
{
776+
name: "URL exceeds maximum length",
777+
secret: testSecret(
778+
withName("proxy-secret"),
779+
withData(map[string][]byte{
780+
secrets.KeyAddress: []byte("http://proxy.example.com/" + string(make([]byte, 2049))),
781+
}),
782+
),
783+
errMsg: "secret 'default/proxy-secret': proxy URL exceeds maximum length of 2048 characters",
784+
},
755785
}
756786

757787
for _, tt := range tests {

tests/integration/go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ require (
2222
github.com/fluxcd/pkg/cache v0.11.0
2323
github.com/fluxcd/pkg/git v0.36.0
2424
github.com/fluxcd/pkg/git/gogit v0.40.0
25-
github.com/fluxcd/pkg/runtime v0.86.0
25+
github.com/fluxcd/pkg/runtime v0.87.0
2626
github.com/fluxcd/test-infra/tftestenv v0.0.0-20250626232827-e0ca9c3f8d7b
2727
github.com/go-git/go-git/v5 v5.16.2
2828
github.com/google/go-containerregistry v0.20.6

0 commit comments

Comments
 (0)