From 3a72243b94f05c95c069a59468b392e9070c97f5 Mon Sep 17 00:00:00 2001 From: Diogo-fj-rocha <104084969+cx-diogo-rocha@users.noreply.github.com> Date: Tue, 10 Feb 2026 15:28:09 +0000 Subject: [PATCH 1/8] correct regexTarget description in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f80975ee..990f62e1 100644 --- a/README.md +++ b/README.md @@ -372,7 +372,7 @@ Other fields are optional and can be seen in the example bellow of a file with a allowLists: # allowed values to ignore if matched - description: Allowlist for Custom Rule matchCondition: OR # Can be AND or OR. determines whether all criteria in the allowList must match. Defaults to OR if not specified - regexTarget: match - # Can be match or line. Determines whether the regexes in allowList are tested against the rule.Regex match or the full line being scanned. Defaults to "match" if not specified + regexTarget: match - # Can be 'match', 'line' or simply empty/omitted. If 'match', regexes in allowList are tested against the rule.Regex match. If 'line', against the line where the secret was found. If empty/omitted, against the secret itself. Keep in mind, if the rule.Regex has capture groups, the secret is found by one of those capture groups (first capture group by default, or the capture group identified by, if defined, rule.secretGroup) regexes: # allowed regex patterns - (?i)(?:access(?:ibility|or)|access[_.-]?id|random[_.-]?access|api[_.-]?(?:id|name|version)|rapid|capital|[a-z0-9-]*?api[a-z0-9-]*?:jar:|author|X-MS-Exchange-Organization-Auth|Authentication-Results|(?:credentials?[_.-]?id|withCredentials)|(?:25[0-5]|2[0-4]\d|1?\d?\d)(?:\.(?:25[0-5]|2[0-4]\d|1?\d?\d)){3}|(?:bucket|foreign|hot|idx|natural|primary|pub(?:lic)?|schema|sequence)[_.-]?key|(?:turkey)|key[_.-]?(?:alias|board|code|frame|id|length|mesh|name|pair|press(?:ed)?|ring|selector|signature|size|stone|storetype|word|up|down|left|right)|KeyVault(?:[A-Za-z]*?(?:Administrator|Reader|Contributor|Owner|Operator|User|Officer))\s*[:=]\s*['"]?[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}['"]?|key[_.-]?vault[_.-]?(?:id|name)|keyVaultToStoreSecrets|key(?:store|tab)[_.-]?(?:file|path)|issuerkeyhash|(?-i:[DdMm]onkey|[DM]ONKEY)|keying|(?:secret)[_.-]?(?:length|name|size)|UserSecretsId|(?:csrf)[_.-]?token|(?:io\.jsonwebtoken[ \t]?:[ From 533a52b3487bd532f5e49eba29bdeb3d214d08a0 Mon Sep 17 00:00:00 2001 From: Diogo-fj-rocha <104084969+cx-diogo-rocha@users.noreply.github.com> Date: Tue, 10 Feb 2026 17:28:01 +0000 Subject: [PATCH 2/8] Update go version --- Dockerfile | 4 ++-- go.mod | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 1d9acc07..936fa614 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ # and "Missing User Instruction" since 2ms container is stopped after scan # Builder image -FROM checkmarx/go:1.25.3-r0-b47cbbc1194cd0@sha256:b47cbbc1194cd0d801fe7739fca12091d610117b0d30c32b52fc900217a0821a AS builder +FROM checkmarx/go:1.25.7-r0-e1219fc40b8bb2@sha256:e1219fc40b8bb2ff52bece1e0644c3bfe6bf4ef5ff34259a4c297e3f36418a1d AS builder WORKDIR /app @@ -20,7 +20,7 @@ COPY . . RUN GOOS=linux GOARCH=amd64 go build -buildvcs=false -ldflags="-s -w" -a -o /app/2ms . # Runtime image -FROM checkmarx/git:2.49.0-r2-d7ebbe7c56dc47@sha256:d7ebbe7c56dc478c08aba611c35b30689090d28605d83130ce4d1e15a84f0389 +FROM checkmarx/git:2.53.0-r0-a633961d3a877d@sha256:a633961d3a877de3368632e9bf2d5ba38cc3dc586fdce6090185f224bce45c30 WORKDIR /app diff --git a/go.mod b/go.mod index 79253d05..eabb5604 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/checkmarx/2ms/v5 -go 1.25.6 +go 1.25.7 replace ( golang.org/x/oauth2 => golang.org/x/oauth2 v0.30.0 From ae611bbc8eda8526ec3109addcf8948ca6930e35 Mon Sep 17 00:00:00 2001 From: Diogo-fj-rocha <104084969+cx-diogo-rocha@users.noreply.github.com> Date: Thu, 19 Feb 2026 17:13:34 +0000 Subject: [PATCH 3/8] Update dockerfile tags --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 936fa614..0b6c483c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ # and "Missing User Instruction" since 2ms container is stopped after scan # Builder image -FROM checkmarx/go:1.25.7-r0-e1219fc40b8bb2@sha256:e1219fc40b8bb2ff52bece1e0644c3bfe6bf4ef5ff34259a4c297e3f36418a1d AS builder +FROM checkmarx/go:1.25.7-r0-b270bc965b34b4@sha256:b270bc965b34b4ffec624413bc1f1830c58c0abb142580ca76d42116b3b06764 AS builder WORKDIR /app @@ -20,7 +20,7 @@ COPY . . RUN GOOS=linux GOARCH=amd64 go build -buildvcs=false -ldflags="-s -w" -a -o /app/2ms . # Runtime image -FROM checkmarx/git:2.53.0-r0-a633961d3a877d@sha256:a633961d3a877de3368632e9bf2d5ba38cc3dc586fdce6090185f224bce45c30 +FROM checkmarx/git:2.53.0-r0-dadf19ec31d471@sha256:dadf19ec31d4711eeace2763e89511693b36ba0ea5c9e12a763978b4b29ddba0 WORKDIR /app From 6cb7d3500f51ecf88abda82f81c065a076696f76 Mon Sep 17 00:00:00 2001 From: Diogo-fj-rocha <104084969+cx-diogo-rocha@users.noreply.github.com> Date: Thu, 19 Feb 2026 17:37:51 +0000 Subject: [PATCH 4/8] Ignore linter gosec false positives --- lib/utils/http.go | 1 + plugins/confluence_client.go | 2 ++ 2 files changed, 3 insertions(+) diff --git a/lib/utils/http.go b/lib/utils/http.go index a7d7a256..97e7b188 100644 --- a/lib/utils/http.go +++ b/lib/utils/http.go @@ -40,6 +40,7 @@ func HttpRequest(method, url string, authorization IAuthorizationHeader, retry R // TODO: do not recreate this client for each request client := &http.Client{} + // #nosec G107 -- URL is intentionally user-provided for plugin API calls to external services response, err := client.Do(request) if err != nil { return nil, response, fmt.Errorf("unable to send http request %w", err) diff --git a/plugins/confluence_client.go b/plugins/confluence_client.go index 71fe9847..d5f0e207 100644 --- a/plugins/confluence_client.go +++ b/plugins/confluence_client.go @@ -190,6 +190,7 @@ func (c *httpConfluenceClient) discoverCloudID(ctx context.Context) (string, err if err != nil { return "", fmt.Errorf("build tenant_info request: %w", err) } + // #nosec G704 -- URL is intentionally user-provided for plugin API calls to external services resp, err := c.httpClient.Do(req) if err != nil { return "", ErrBaseURLInvalidOrUnreachable @@ -475,6 +476,7 @@ func (c *httpConfluenceClient) getJSON(ctx context.Context, reqURL string) ([]by } req.Header.Set("Accept", "application/json") + // #nosec G704 -- URL is intentionally user-provided for plugin API calls to external services resp, err := c.httpClient.Do(req) if err != nil { return nil, nil, fmt.Errorf("http get: %w", err) From 33e30582d00113d302e732b5ba08382dd853f81c Mon Sep 17 00:00:00 2001 From: Diogo-fj-rocha <104084969+cx-diogo-rocha@users.noreply.github.com> Date: Thu, 19 Feb 2026 17:45:44 +0000 Subject: [PATCH 5/8] Ignore linter gosec false positives --- engine/validation/alibaba.go | 1 + lib/utils/http.go | 2 +- plugins/confluence_client.go | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/engine/validation/alibaba.go b/engine/validation/alibaba.go index 228a00e6..a44a7f2f 100644 --- a/engine/validation/alibaba.go +++ b/engine/validation/alibaba.go @@ -69,6 +69,7 @@ func alibabaRequest(accessKey, secretKey string) (secrets.ValidationResult, erro req.URL.RawQuery = params.Encode() client := &http.Client{} + // #nosec G704 -- URL is hardcoded to Alibaba API, only query params contain credentials being validated resp, err := client.Do(req) if err != nil { return secrets.UnknownResult, err diff --git a/lib/utils/http.go b/lib/utils/http.go index 97e7b188..2c1e51e4 100644 --- a/lib/utils/http.go +++ b/lib/utils/http.go @@ -40,7 +40,7 @@ func HttpRequest(method, url string, authorization IAuthorizationHeader, retry R // TODO: do not recreate this client for each request client := &http.Client{} - // #nosec G107 -- URL is intentionally user-provided for plugin API calls to external services + // #nosec G704 -- URL is intentionally user-provided for plugin API calls to external services response, err := client.Do(request) if err != nil { return nil, response, fmt.Errorf("unable to send http request %w", err) diff --git a/plugins/confluence_client.go b/plugins/confluence_client.go index d5f0e207..e9c4c017 100644 --- a/plugins/confluence_client.go +++ b/plugins/confluence_client.go @@ -527,7 +527,7 @@ func (c *httpConfluenceClient) getJSONStream(ctx context.Context, reqURL string) req.SetBasicAuth(c.username, c.token) } req.Header.Set("Accept", "application/json") - + // #nosec G704 -- URL is intentionally user-provided for plugin API calls to external services resp, err := c.httpClient.Do(req) if err != nil { return nil, nil, fmt.Errorf("http get: %w", err) From f6066cd042a61b0580b597c6e6299f4ff28e38da Mon Sep 17 00:00:00 2001 From: Diogo-fj-rocha <104084969+cx-diogo-rocha@users.noreply.github.com> Date: Thu, 19 Feb 2026 17:58:36 +0000 Subject: [PATCH 6/8] More ignores on linter gosec false positives --- engine/validation/client.go | 1 + engine/validation/gcp.go | 1 + 2 files changed, 2 insertions(+) diff --git a/engine/validation/client.go b/engine/validation/client.go index cb479115..839bfbdd 100644 --- a/engine/validation/client.go +++ b/engine/validation/client.go @@ -14,6 +14,7 @@ func sendValidationRequest(endpoint, authorization string) (*http.Response, erro // TODO: do not recreate this client for each request client := &http.Client{} + // #nosec G704 -- URL is hardcoded in both github and gitlab uses, only query params contain credentials being validated resp, err := client.Do(req) if err != nil { return nil, err diff --git a/engine/validation/gcp.go b/engine/validation/gcp.go index 891090fc..83be8e9e 100644 --- a/engine/validation/gcp.go +++ b/engine/validation/gcp.go @@ -32,6 +32,7 @@ func validateGCP(s *secrets.Secret) (secrets.ValidationResult, string) { return secrets.UnknownResult, "" } + // #nosec G704 -- URL is hardcoded to GCP API, only query params contain credentials being validated client := &http.Client{} resp, err := client.Do(req) if err != nil { From 9b0e5f1fedd0b7cbfd4a1cd57065b4f2c3713e04 Mon Sep 17 00:00:00 2001 From: Diogo-fj-rocha <104084969+cx-diogo-rocha@users.noreply.github.com> Date: Thu, 19 Feb 2026 18:05:14 +0000 Subject: [PATCH 7/8] Fixed wrongly placed comment --- engine/validation/gcp.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/engine/validation/gcp.go b/engine/validation/gcp.go index 83be8e9e..53298da5 100644 --- a/engine/validation/gcp.go +++ b/engine/validation/gcp.go @@ -31,9 +31,8 @@ func validateGCP(s *secrets.Secret) (secrets.ValidationResult, string) { log.Warn().Err(err).Msg("Failed to validate secret") return secrets.UnknownResult, "" } - - // #nosec G704 -- URL is hardcoded to GCP API, only query params contain credentials being validated client := &http.Client{} + // #nosec G704 -- URL is hardcoded to GCP API, only query params contain credentials being validated resp, err := client.Do(req) if err != nil { log.Warn().Err(err).Msg("Failed to validate secret") From a5e3eccec5d0fc9728ee9fd7bf5b698f895ba9ed Mon Sep 17 00:00:00 2001 From: Diogo-fj-rocha <104084969+cx-diogo-rocha@users.noreply.github.com> Date: Fri, 20 Feb 2026 11:10:47 +0000 Subject: [PATCH 8/8] Reworded and reformatted regexTarget option description --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 990f62e1..4d2087b2 100644 --- a/README.md +++ b/README.md @@ -372,7 +372,10 @@ Other fields are optional and can be seen in the example bellow of a file with a allowLists: # allowed values to ignore if matched - description: Allowlist for Custom Rule matchCondition: OR # Can be AND or OR. determines whether all criteria in the allowList must match. Defaults to OR if not specified - regexTarget: match - # Can be 'match', 'line' or simply empty/omitted. If 'match', regexes in allowList are tested against the rule.Regex match. If 'line', against the line where the secret was found. If empty/omitted, against the secret itself. Keep in mind, if the rule.Regex has capture groups, the secret is found by one of those capture groups (first capture group by default, or the capture group identified by, if defined, rule.secretGroup) + regexTarget: match # Specifies what to test allowList regexes against. Options: 'match', 'line', or empty/omitted. + # - 'match': test against the full rule.Regex match + # - 'line': test against the entire line where the secret was found + # - empty/omitted: test against the secret itself (which is the first capture group from rule.Regex, or the group specified by rule.secretGroup if defined) regexes: # allowed regex patterns - (?i)(?:access(?:ibility|or)|access[_.-]?id|random[_.-]?access|api[_.-]?(?:id|name|version)|rapid|capital|[a-z0-9-]*?api[a-z0-9-]*?:jar:|author|X-MS-Exchange-Organization-Auth|Authentication-Results|(?:credentials?[_.-]?id|withCredentials)|(?:25[0-5]|2[0-4]\d|1?\d?\d)(?:\.(?:25[0-5]|2[0-4]\d|1?\d?\d)){3}|(?:bucket|foreign|hot|idx|natural|primary|pub(?:lic)?|schema|sequence)[_.-]?key|(?:turkey)|key[_.-]?(?:alias|board|code|frame|id|length|mesh|name|pair|press(?:ed)?|ring|selector|signature|size|stone|storetype|word|up|down|left|right)|KeyVault(?:[A-Za-z]*?(?:Administrator|Reader|Contributor|Owner|Operator|User|Officer))\s*[:=]\s*['"]?[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}['"]?|key[_.-]?vault[_.-]?(?:id|name)|keyVaultToStoreSecrets|key(?:store|tab)[_.-]?(?:file|path)|issuerkeyhash|(?-i:[DdMm]onkey|[DM]ONKEY)|keying|(?:secret)[_.-]?(?:length|name|size)|UserSecretsId|(?:csrf)[_.-]?token|(?:io\.jsonwebtoken[ \t]?:[