From f3cd3c5ceb3a3e328aa7eed3fde72b3ee67c59c8 Mon Sep 17 00:00:00 2001 From: elsapet Date: Thu, 4 Jul 2024 09:49:37 +0200 Subject: [PATCH] fix(golang): permissive regex rule for validation purposes --- rules/go/lang/permissive_regex_validation.yml | 33 ++++++++++++------- .../testdata/main.go | 20 ++++++++--- 2 files changed, 37 insertions(+), 16 deletions(-) diff --git a/rules/go/lang/permissive_regex_validation.yml b/rules/go/lang/permissive_regex_validation.yml index e353a6954..fd9f94ac6 100644 --- a/rules/go/lang/permissive_regex_validation.yml +++ b/rules/go/lang/permissive_regex_validation.yml @@ -1,17 +1,26 @@ patterns: - - pattern: | - $.$($$<...>) + - pattern: $.$($<...>) filters: - - variable: REGEXP - detection: go_lang_permissive_regex_validation_regexp + - variable: PERMISSIVE_REGEXP + detection: go_lang_permissive_regex_validation_permissive_regexp - variable: METHOD values: - - Compile - - MustCompile - - not: - variable: PATTERN - string_regex: \A.\\A.*\\[zZ].\z + - Match + - MatchString auxiliary: + - id: go_lang_permissive_regex_validation_permissive_regexp + patterns: + - pattern: $.$($$<...>) + filters: + - variable: REGEXP + detection: go_lang_permissive_regex_validation_regexp + - variable: METHOD + values: + - Compile + - MustCompile + - not: + variable: PATTERN + string_regex: \A.\\A.*\\[zZ].\z - id: go_lang_permissive_regex_validation_regexp patterns: - import $"regexp" @@ -22,15 +31,15 @@ auxiliary: languages: - go metadata: - description: "Missing validation for regular expression" + description: Permissive regular expression used in matching remediation_message: |- ## Description - When using regular expressions for validation, it's crucial to specify the start and end of the text boundaries. This ensures the entire text is validated, not just parts of it. Use \A and \z (or \Z) over ^ and $ to specify text boundaries, because these accurately mark the beginning and end of the text, even in multiline mode. + When matching with regular expressions -- especially for validation purposes -- it is crucial to specify the start and end of the text boundaries. This ensures the entire text is validated, not just parts of it, and prevents attackers from bypassing validation with partially matching input. Use \A and \z (or \Z) over ^ and $ to specify text boundaries, because these accurately mark the beginning and end of the text, even in multiline mode. ## Remediations - - **Do not** use regular expressions without specifying start and end boundaries. This can lead to incomplete validation. + - **Do not** use regular expressions for validation without specifying start and end boundaries. This can lead to partial matches being considered valid, when they may contain unsafe input. ```go regexp.MustCompile("foo") // unsafe ``` diff --git a/tests/go/lang/permissive_regex_validation/testdata/main.go b/tests/go/lang/permissive_regex_validation/testdata/main.go index a8632a094..8e305cea3 100644 --- a/tests/go/lang/permissive_regex_validation/testdata/main.go +++ b/tests/go/lang/permissive_regex_validation/testdata/main.go @@ -5,11 +5,23 @@ import ( "regexp" ) -func bad() { +func permissiveRegex(input string) { + re := regexp.MustCompile("[a-zA-Z0-9]*") + + // likely not validation - we ignore this + re.ReplaceAllString(input, "foo") + + // bearer:expected go_lang_permissive_regex_validation + re.Match([]byte(input)) // bearer:expected go_lang_permissive_regex_validation - _ = regexp.MustCompile("[a-zA-Z0-9]*") + re.MatchString(input) } -func good() { - _ = regexp.MustCompile(`\A[a-zA-Z0-9]*\z`) +func goodRegexp(input string) { + re := regexp.MustCompile(`\A[a-zA-Z0-9]*\z`) + if re.MatchString(input) { + // continue with valid string + } else { + // handle invalid string + } }