git.iko.soy/typeable/oauth2-proxy
on master help sign in
fix: regex substitution for $ signs in upstream path handling before running envsubst (#2524)

* Perform a regex replace of $NUM to $$NUM before running envsubst * Perform a regex replace of $NUM to $$NUM before running envsubst * add test case; fix linter warnings; add method documentation Signed-off-by: Jan Larwig <jan@larwig.com> * add changelog entry Signed-off-by: Jan Larwig <jan@larwig.com> --------- Signed-off-by: Jan Larwig <jan@larwig.com> Co-authored-by: Jan Larwig <jan@larwig.com>

commit137e59d52668e3fc5d670dfbb6c3d667739e22e3 authorAshkan Daie <1415513+dashkan@users.noreply.github.com> dateMon 21 Jul 2025, 23:52 (1 year ago) parenta88306b
3 files changed+45−3
CHANGELOG.md+1 pkg/apis/options/load.go+19−3 pkg/apis/options/load_test.go+25
CHANGELOG.md+1
@@ -12,6 +12,7 @@
1212- [#2605](https://github.com/oauth2-proxy/oauth2-proxy/pull/2605) fix: show login page on broken cookie (@Primexz)
1313- [#2743](https://github.com/oauth2-proxy/oauth2-proxy/pull/2743) feat: allow use more possible google admin-sdk api scopes (@BobDu)
1414- [#2359](https://github.com/oauth2-proxy/oauth2-proxy/pull/2359) feat: add SourceHut (sr.ht) provider(@bitfehler)
15+-[#2524](https://github.com/oauth2-proxy/oauth2-proxy/pull/2524) fix: regex substitution for $ signs in upstream path handling before running envsubst (@dashkan / @tuunit)
1516
1617# V7.10.0
1718
pkg/apis/options/load.go+19−3
@@ -5,6 +5,7 @@ import (
55 "fmt"
66 "os"
77 "reflect"
8+ "regexp"
89 "strings"
910
1011 "github.com/a8m/envsubst"
@@ -155,7 +156,8 @@ func LoadYAML(configFileName string, into interface{}) error {
155156 return nil
156157}
157158
158−// Performs the heavy lifting of the LoadYaml function
159+// loadAndParseYaml reads the config from the filesystem and
160+// execute the environment variable substitution
159161func loadAndParseYaml(configFileName string) ([]byte, error) {
160162 if configFileName == "" {
161163 return nil, errors.New("no configuration file provided")
@@ -166,12 +168,26 @@ func loadAndParseYaml(configFileName string) ([]byte, error) {
166168 return nil, fmt.Errorf("unable to load config file: %w", err)
167169 }
168170
169− // We now parse over the yaml with env substring, and fill in the ENV's
170− buffer, err := envsubst.Bytes(unparsedBuffer)
171+ modifiedBuffer, err := normalizeSubstitution(unparsedBuffer)
172+ if err != nil {
173+ return nil, fmt.Errorf("error normalizing substitution string : %w", err)
174+ }
175+
176+ buffer, err := envsubst.Bytes(modifiedBuffer)
171177 if err != nil {
172178 return nil, fmt.Errorf("error in substituting env variables : %w", err)
173179 }
174180
175181 return buffer, nil
182+}
183+
184+// normalizeSubstitution normalizes dollar signs ($) with numerals like
185+// $1 or $2 properly by correctly escaping them
186+func normalizeSubstitution(unparsedBuffer []byte) ([]byte, error) {
187+ unparsedString := string(unparsedBuffer)
188+
189+ regexPattern := regexp.MustCompile(`\$(\d+)`)
176190
191+ substitutedString := regexPattern.ReplaceAllString(unparsedString, `$$$$1`)
192+ return []byte(substitutedString), nil
177193}
pkg/apis/options/load_test.go+25
@@ -487,6 +487,31 @@ sub:
487487 StringOption: "Bob",
488488 },
489489 }),
490+ Entry("with a config file containing $ signs for things other than environment variables", loadYAMLTableInput{
491+ configFile: []byte(`
492+stringOption: /$1
493+stringSliceOption:
494+- /$1
495+- ^/(.*)$
496+- api/$1
497+- api/(.*)$
498+- ^/api/(.*)$
499+- /api/$1`),
500+ input: &TestOptions{},
501+ expectedOutput: &TestOptions{
502+ StringOption: "/$1",
503+ TestOptionSubStruct: TestOptionSubStruct{
504+ StringSliceOption: []string{
505+ "/$1",
506+ "^/(.*)$",
507+ "api/$1",
508+ "api/(.*)$",
509+ "^/api/(.*)$",
510+ "/api/$1",
511+ },
512+ },
513+ },
514+ }),
490515 )
491516 })
492517