4
0
Эх сурвалжийг харах

Feat/nuget config password rule (#1540)

* feat: add new rule nuget-config-password

* docs: correct function names within CONTRIBUTING.md
Roger Meier 1 жил өмнө
parent
commit
f6e549901c

+ 11 - 11
CONTRIBUTING.md

@@ -39,7 +39,7 @@ If you want to add a new rule to the [default Gitleaks configuration](https://gi
 
 
 
 
            // Regex used for detecting secrets. See regex section below for more details
            // Regex used for detecting secrets. See regex section below for more details
-           Regex: generateSemiGenericRegex([]string{"beamer"}, `b_[a-z0-9=_\-]{44}`, true)
+           Regex: GenerateSemiGenericRegex([]string{"beamer"}, `b_[a-z0-9=_\-]{44}`, true)
 
 
            // Keywords used for string matching on fragments (think of this as a prefilter)
            // Keywords used for string matching on fragments (think of this as a prefilter)
            Keywords: []string{"beamer"},
            Keywords: []string{"beamer"},
@@ -57,32 +57,32 @@ If you want to add a new rule to the [default Gitleaks configuration](https://gi
    This file should be fairly self-explanatory except for a few items;
    This file should be fairly self-explanatory except for a few items;
    regex and secret generation. To help with maintence, _most_ rules should
    regex and secret generation. To help with maintence, _most_ rules should
    be uniform. The functions,
    be uniform. The functions,
-   [`generateSemiGenericRegex`](https://github.com/zricethezav/gitleaks/blob/master/cmd/generate/config/rules/rule.go#L31) and [`generateUniqueTokenRegex`](https://github.com/zricethezav/gitleaks/blob/master/cmd/generate/config/rules/rule.go#L44) will generate rules
+   [`GenerateSemiGenericRegex`](https://github.com/zricethezav/gitleaks/blob/master/cmd/generate/config/rules/rule.go#L31) and [`GenerateUniqueTokenRegex`](https://github.com/zricethezav/gitleaks/blob/master/cmd/generate/config/rules/rule.go#L44) will generate rules
    that follow defined patterns.
    that follow defined patterns.
 
 
    The function signatures look like this:
    The function signatures look like this:
 
 
    ```golang
    ```golang
-   func generateSemiGenericRegex(identifiers []string, secretRegex string, isCaseInsensitive bool) *regexp.Regexp
+   func GenerateSemiGenericRegex(identifiers []string, secretRegex string, isCaseInsensitive bool) *regexp.Regexp
 
 
-   func generateUniqueTokenRegex(secretRegex string, isCaseInsensitive bool) *regexp.Regexp
+   func GenerateUniqueTokenRegex(secretRegex string, isCaseInsensitive bool) *regexp.Regexp
    ```
    ```
 
 
-   `generateSemiGenericRegex` accepts a list of identifiers, a regex, and a boolean indicating whether the pattern should be case-insensitive.
+   `GenerateSemiGenericRegex` accepts a list of identifiers, a regex, and a boolean indicating whether the pattern should be case-insensitive.
    The list of identifiers _should_ match the list of `Keywords` in the rule
    The list of identifiers _should_ match the list of `Keywords` in the rule
-   definition above. Both `identifiers` in the `generateSemiGenericRegex`
+   definition above. Both `identifiers` in the `GenerateSemiGenericRegex`
    function _and_ `Keywords` act as filters for Gitleaks telling the program
    function _and_ `Keywords` act as filters for Gitleaks telling the program
    "_at least one of these strings must be present to be considered a leak_"
    "_at least one of these strings must be present to be considered a leak_"
 
 
-   `generateUniqueToken` just accepts a regex and a boolean indicating whether the pattern should be case-insensitive. If you are writing a rule for a
+   `GenerateUniqueTokenRegex` just accepts a regex and a boolean indicating whether the pattern should be case-insensitive. If you are writing a rule for a
    token that is unique enough not to require an identifier then you can use
    token that is unique enough not to require an identifier then you can use
    this function. For example, Pulumi's API Token has the prefix `pul-` which is
    this function. For example, Pulumi's API Token has the prefix `pul-` which is
-   unique enough to use `generateUniqueToken`. But something like Beamer's API
-   token that has a `b_` prefix is not unique enough to use `generateUniqueToken`,
-   so instead we use `generateSemiGenericRegex` and require a `beamer`
+   unique enough to use `GenerateUniqueTokenRegex`. But something like Beamer's API
+   token that has a `b_` prefix is not unique enough to use `GenerateUniqueTokenRegex`,
+   so instead we use `GenerateSemiGenericRegex` and require a `beamer`
    identifier is part of the rule.
    identifier is part of the rule.
    If a token's prefix has more than `3` characters then you could
    If a token's prefix has more than `3` characters then you could
-   probably get away with using `generateUniqueToken`.
+   probably get away with using `GenerateUniqueTokenRegex`.
 
 
    Last thing you'll want to hit before we move on from this file is the
    Last thing you'll want to hit before we move on from this file is the
    validation part. You can use `generateSampleSecret` to create a secret for the
    validation part. You can use `generateSampleSecret` to create a secret for the

+ 1 - 0
cmd/generate/config/main.go

@@ -138,6 +138,7 @@ func main() {
 		rules.NewRelicBrowserAPIKey(),
 		rules.NewRelicBrowserAPIKey(),
 		rules.NewRelicInsertKey(),
 		rules.NewRelicInsertKey(),
 		rules.NPM(),
 		rules.NPM(),
+		rules.NugetConfigPassword(),
 		rules.NytimesAccessToken(),
 		rules.NytimesAccessToken(),
 		rules.OktaAccessToken(),
 		rules.OktaAccessToken(),
 		rules.OpenAI(),
 		rules.OpenAI(),

+ 48 - 0
cmd/generate/config/rules/nuget.go

@@ -0,0 +1,48 @@
+package rules
+
+import (
+	"regexp"
+
+	"github.com/zricethezav/gitleaks/v8/cmd/generate/config/utils"
+
+	"github.com/zricethezav/gitleaks/v8/config"
+)
+
+func NugetConfigPassword() *config.Rule {
+	r := config.Rule{
+		Description: "Identified a password within a Nuget config file, potentially compromising package management access.",
+		RuleID:      "nuget-config-password",
+		Regex:       regexp.MustCompile(`(?i)<add key=\"(?:(?:ClearText)?Password)\"\s*value=\"(.{8,})\"\s*/>`),
+		Path:        regexp.MustCompile(`(?i)nuget\.config$`),
+		Keywords:    []string{"<add key="},
+		Entropy:     1,
+		Allowlist: config.Allowlist{
+			Regexes: []*regexp.Regexp{
+				// samples from https://learn.microsoft.com/en-us/nuget/reference/nuget-config-file
+				regexp.MustCompile(`33f!!lloppa`),
+				regexp.MustCompile(`hal\+9ooo_da!sY`),
+				// exclude environment variables
+				regexp.MustCompile(`^\%\S.*\%$`),
+			},
+		},
+	}
+
+	tps := map[string]string{
+		"nuget.config": `<add key="Password" value="CleartextPassword1" />`,
+		"Nuget.config": `<add key="ClearTextPassword" value="CleartextPassword1" />`,
+		"Nuget.Config": `<add key="ClearTextPassword" value="TestSourcePassword" />`,
+		"Nuget.COnfig": `<add key="ClearTextPassword" value="TestSource-Password" />`,
+		"Nuget.CONfig": `<add key="ClearTextPassword" value="TestSource%Password" />`,
+		"Nuget.CONFig": `<add key="ClearTextPassword" value="TestSource%Password%" />`,
+	}
+
+	fps := map[string]string{
+		"some.xml":     `<add key="Password" value="CleartextPassword1" />`,            // wrong filename
+		"nuget.config": `<add key="ClearTextPassword" value="XXXXXXXXXXX" />`,          // low entropy
+		"Nuget.config": `<add key="ClearTextPassword" value="abc" />`,                  // too short
+		"Nuget.Config": `<add key="ClearTextPassword" value="%TestSourcePassword%" />`, // environment variable
+		"NUget.Config": `<add key="ClearTextPassword" value="33f!!lloppa" />`,          // known sample
+		"NUGet.Config": `<add key="ClearTextPassword" value="hal+9ooo_da!sY" />`,       // known sample
+	}
+	return utils.ValidateWithPaths(r, tps, fps)
+}

+ 16 - 0
config/gitleaks.toml

@@ -2442,6 +2442,22 @@ keywords = [
     "npm_",
     "npm_",
 ]
 ]
 
 
+[[rules]]
+id = "nuget-config-password"
+description = "Identified a password within a Nuget config file, potentially compromising package management access."
+regex = '''(?i)<add key=\"(?:(?:ClearText)?Password)\"\s*value=\"(.{8,})\"\s*/>'''
+path = '''(?i)nuget\.config$'''
+entropy = 1
+keywords = [
+    "<add key=",
+]
+
+[rules.allowlist]
+
+regexes = [
+    '''33f!!lloppa''','''hal\+9ooo_da!sY''','''^\%\S.*\%$''',
+]
+
 [[rules]]
 [[rules]]
 id = "nytimes-access-token"
 id = "nytimes-access-token"
 description = "Detected a Nytimes Access Token, risking unauthorized access to New York Times APIs and content services."
 description = "Detected a Nytimes Access Token, risking unauthorized access to New York Times APIs and content services."