diff --git a/.gitignore b/.gitignore index 1849589c4..b398dc87e 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ yarn-debug.log* yarn-error.log* lerna-debug.log* package-lock.json +/git-proxy-test # Diagnostic reports (https://nodejs.org/api/report.html) diff --git a/.husky/commit-msg b/.husky/commit-msg index 53b8922aa..470809b9b 100755 --- a/.husky/commit-msg +++ b/.husky/commit-msg @@ -1,4 +1,2 @@ -#!/usr/bin/env sh -. "$(dirname -- "$0")/_/husky.sh" npx --no -- commitlint --edit ${1} && npm run lint diff --git a/gitleaks.toml b/gitleaks.toml new file mode 100644 index 000000000..33e8794fa --- /dev/null +++ b/gitleaks.toml @@ -0,0 +1,3017 @@ +# This file has been auto-generated. Do not edit manually. +# If you would like to contribute new rules, please use +# cmd/generate/config/main.go and follow the contributing guidelines +# at https://github.com/gitleaks/gitleaks/blob/master/CONTRIBUTING.md + +# This is the default gitleaks configuration file. +# Rules and allowlists are defined within this file. +# Rules instruct gitleaks on what should be considered a secret. +# Allowlists instruct gitleaks on what is allowed, i.e. not a secret. + +title = "gitleaks config" + +[allowlist] +description = "global allow lists" +regexes = [ + '''(?i)^true|false|null$''', + '''^(?i:a+|b+|c+|d+|e+|f+|g+|h+|i+|j+|k+|l+|m+|n+|o+|p+|q+|r+|s+|t+|u+|v+|w+|x+|y+|z+|\*+|\.+)$''', + '''^\$(\d+|{\d+})$''', + '''^\$([A-Z_]+|[a-z_]+)$''', + '''^\${([A-Z_]+|[a-z_]+)}$''', + '''^\{\{[ \t]*[\w ().|]+[ \t]*}}$''', + '''^\$\{\{[ \t]*((env|github|secrets|vars)(\.[A-Za-z]\w+)+[\w "'&./=|]*)[ \t]*}}$''', + '''^%([A-Z_]+|[a-z_]+)%$''', + '''^%[+\-# 0]?[bcdeEfFgGoOpqstTUvxX]$''', + '''^\{\d{0,2}}$''', + '''^@([A-Z_]+|[a-z_]+)@$''', +] +paths = [ + '''gitleaks\.toml''', + '''(?i)\.(bmp|gif|jpe?g|svg|tiff?)$''', + '''\.(eot|[ot]tf|woff2?)$''', + '''(.*?)(doc|docx|zip|xls|pdf|bin|socket|vsidx|v2|suo|wsuo|.dll|pdb|exe|gltf)$''', + '''go\.(mod|sum|work(\.sum)?)$''', + '''(^|/)vendor/modules\.txt$''', + '''(^|/)vendor/(github\.com|golang\.org/x|google\.golang\.org|gopkg\.in|istio\.io|k8s\.io|sigs\.k8s\.io)/.*$''', + '''(^|/)gradlew(\.bat)?$''', + '''(^|/)gradle\.lockfile$''', + '''(^|/)mvnw(\.cmd)?$''', + '''(^|/)\.mvn/wrapper/MavenWrapperDownloader\.java$''', + '''(^|/)node_modules/.*?$''', + '''(^|/)package-lock\.json$''', + '''(^|/)yarn\.lock$''', + '''(^|/)pnpm-lock\.yaml$''', + '''(^|/)npm-shrinkwrap\.json$''', + '''(^|/)bower_components/.*?$''', + '''(^|/)(angular|jquery(-?ui)?|plotly|swagger-?ui)[a-zA-Z0-9.-]*(\.min)?\.js(\.map)?$''', + '''(^|/)(Pipfile|poetry)\.lock$''', + '''(?i)/?(v?env|virtualenv)/lib(64)?/.+$''', + '''(?i)(^|/)(lib(64)?/python[23](\.\d{1,2})+/|python/[23](\.\d{1,2})+/lib(64)?/).+$''', + '''(?i)(^|/)[a-z0-9_.]+-[0-9.]+\.dist-info/.+$''', + '''(^|/)vendor/(bundle|ruby)/.*?$''', + '''\.gem$''', + '''verification-metadata.xml''', + '''Database.refactorlog''', +] +stopwords = [ + "014df517-39d1-4453-b7b3-9930c563627c", +] + +[[rules]] +id = "1password-service-account-token" +description = "Uncovered a possible 1Password service account token, potentially compromising access to secrets in vaults." +regex = '''ops_eyJ[a-zA-Z0-9+/]{250,}={0,3}''' +entropy = 4 +keywords = ["ops_"] + +[[rules]] +id = "adafruit-api-key" +description = "Identified a potential Adafruit API Key, which could lead to unauthorized access to Adafruit services and sensitive data exposure." +regex = '''(?i)[\w.-]{0,50}?(?:adafruit)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9_-]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["adafruit"] + +[[rules]] +id = "adobe-client-id" +description = "Detected a pattern that resembles an Adobe OAuth Web Client ID, posing a risk of compromised Adobe integrations and data breaches." +regex = '''(?i)[\w.-]{0,50}?(?:adobe)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-f0-9]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 2 +keywords = ["adobe"] + +[[rules]] +id = "adobe-client-secret" +description = "Discovered a potential Adobe Client Secret, which, if exposed, could allow unauthorized Adobe service access and data manipulation." +regex = '''\b(p8e-(?i)[a-z0-9]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 2 +keywords = ["p8e-"] + +[[rules]] +id = "age-secret-key" +description = "Discovered a potential Age encryption tool secret key, risking data decryption and unauthorized access to sensitive information." +regex = '''AGE-SECRET-KEY-1[QPZRY9X8GF2TVDW0S3JN54KHCE6MUA7L]{58}''' +keywords = ["age-secret-key-1"] + +[[rules]] +id = "airtable-api-key" +description = "Uncovered a possible Airtable API Key, potentially compromising database access and leading to data leakage or alteration." +regex = '''(?i)[\w.-]{0,50}?(?:airtable)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{17})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["airtable"] + +[[rules]] +id = "algolia-api-key" +description = "Identified an Algolia API Key, which could result in unauthorized search operations and data exposure on Algolia-managed platforms." +regex = '''(?i)[\w.-]{0,50}?(?:algolia)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["algolia"] + +[[rules]] +id = "alibaba-access-key-id" +description = "Detected an Alibaba Cloud AccessKey ID, posing a risk of unauthorized cloud resource access and potential data compromise." +regex = '''\b(LTAI(?i)[a-z0-9]{20})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 2 +keywords = ["ltai"] + +[[rules]] +id = "alibaba-secret-key" +description = "Discovered a potential Alibaba Cloud Secret Key, potentially allowing unauthorized operations and data access within Alibaba Cloud." +regex = '''(?i)[\w.-]{0,50}?(?:alibaba)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{30})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 2 +keywords = ["alibaba"] + +[[rules]] +id = "asana-client-id" +description = "Discovered a potential Asana Client ID, risking unauthorized access to Asana projects and sensitive task information." +regex = '''(?i)[\w.-]{0,50}?(?:asana)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([0-9]{16})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["asana"] + +[[rules]] +id = "asana-client-secret" +description = "Identified an Asana Client Secret, which could lead to compromised project management integrity and unauthorized access." +regex = '''(?i)[\w.-]{0,50}?(?:asana)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["asana"] + +[[rules]] +id = "atlassian-api-token" +description = "Detected an Atlassian API token, posing a threat to project management and collaboration tool security and data confidentiality." +regex = '''[\w.-]{0,50}?(?i:[\w.-]{0,50}?(?:atlassian|confluence|jira)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3})(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-zA-Z0-9]{24})(?:['|\"|\n|\r|\s|\x60|;]|$)|\b(ATATT3[A-Za-z0-9_\-=]{186})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 3.5 +keywords = [ + "atlassian", + "confluence", + "jira", + "atatt3", +] + +[[rules]] +id = "authress-service-client-access-key" +description = "Uncovered a possible Authress Service Client Access Key, which may compromise access control services and sensitive data." +regex = '''\b((?:sc|ext|scauth|authress)_(?i)[a-z0-9]{5,30}\.[a-z0-9]{4,6}\.(?-i:acc)[_-][a-z0-9-]{10,32}\.[a-z0-9+/_=-]{30,120})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 2 +keywords = [ + "sc_", + "ext_", + "scauth_", + "authress_", +] + +[[rules]] +id = "aws-access-token" +description = "Identified a pattern that may indicate AWS credentials, risking unauthorized cloud resource access and data breaches on AWS platforms." +regex = '''\b((?:A3T[A-Z0-9]|AKIA|ASIA|ABIA|ACCA)[A-Z0-9]{16})\b''' +entropy = 3 +keywords = [ + "a3t", + "akia", + "asia", + "abia", + "acca", +] +# NOTE: Gitleaks >= v8.21.0 should use [[rules.allowlists] instead. +[rules.allowlist] +regexes = [ + '''.+EXAMPLE$''', +] + +[[rules]] +id = "azure-ad-client-secret" +description = "Azure AD Client Secret" +regex = '''(?:^|[\\'"\x60\s>=:(,)])([a-zA-Z0-9_~.]{3}\dQ~[a-zA-Z0-9_~.-]{31,34})(?:$|[\\'"\x60\s<),])''' +entropy = 3 +keywords = ["q~"] + +[[rules]] +id = "beamer-api-token" +description = "Detected a Beamer API token, potentially compromising content management and exposing sensitive notifications and updates." +regex = '''(?i)[\w.-]{0,50}?(?:beamer)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}(b_[a-z0-9=_\-]{44})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["beamer"] + +[[rules]] +id = "bitbucket-client-id" +description = "Discovered a potential Bitbucket Client ID, risking unauthorized repository access and potential codebase exposure." +regex = '''(?i)[\w.-]{0,50}?(?:bitbucket)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["bitbucket"] + +[[rules]] +id = "bitbucket-client-secret" +description = "Discovered a potential Bitbucket Client Secret, posing a risk of compromised code repositories and unauthorized access." +regex = '''(?i)[\w.-]{0,50}?(?:bitbucket)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9=_\-]{64})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["bitbucket"] + +[[rules]] +id = "bittrex-access-key" +description = "Identified a Bittrex Access Key, which could lead to unauthorized access to cryptocurrency trading accounts and financial loss." +regex = '''(?i)[\w.-]{0,50}?(?:bittrex)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["bittrex"] + +[[rules]] +id = "bittrex-secret-key" +description = "Detected a Bittrex Secret Key, potentially compromising cryptocurrency transactions and financial security." +regex = '''(?i)[\w.-]{0,50}?(?:bittrex)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["bittrex"] + +[[rules]] +id = "clojars-api-token" +description = "Uncovered a possible Clojars API token, risking unauthorized access to Clojure libraries and potential code manipulation." +regex = '''(?i)CLOJARS_[a-z0-9]{60}''' +entropy = 2 +keywords = ["clojars_"] + +[[rules]] +id = "cloudflare-api-key" +description = "Detected a Cloudflare API Key, potentially compromising cloud application deployments and operational security." +regex = '''(?i)[\w.-]{0,50}?(?:cloudflare)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9_-]{40})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 2 +keywords = ["cloudflare"] + +[[rules]] +id = "cloudflare-global-api-key" +description = "Detected a Cloudflare Global API Key, potentially compromising cloud application deployments and operational security." +regex = '''(?i)[\w.-]{0,50}?(?:cloudflare)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-f0-9]{37})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 2 +keywords = ["cloudflare"] + +[[rules]] +id = "cloudflare-origin-ca-key" +description = "Detected a Cloudflare Origin CA Key, potentially compromising cloud application deployments and operational security." +regex = '''\b(v1\.0-[a-f0-9]{24}-[a-f0-9]{146})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 2 +keywords = [ + "cloudflare", + "v1.0-", +] + +[[rules]] +id = "codecov-access-token" +description = "Found a pattern resembling a Codecov Access Token, posing a risk of unauthorized access to code coverage reports and sensitive data." +regex = '''(?i)[\w.-]{0,50}?(?:codecov)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["codecov"] + +[[rules]] +id = "cohere-api-token" +description = "Identified a Cohere Token, posing a risk of unauthorized access to AI services and data manipulation." +regex = '''[\w.-]{0,50}?(?i:[\w.-]{0,50}?(?:cohere|CO_API_KEY)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3})(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-zA-Z0-9]{40})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 4 +keywords = [ + "cohere", + "co_api_key", +] + +[[rules]] +id = "coinbase-access-token" +description = "Detected a Coinbase Access Token, posing a risk of unauthorized access to cryptocurrency accounts and financial transactions." +regex = '''(?i)[\w.-]{0,50}?(?:coinbase)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9_-]{64})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["coinbase"] + +[[rules]] +id = "confluent-access-token" +description = "Identified a Confluent Access Token, which could compromise access to streaming data platforms and sensitive data flow." +regex = '''(?i)[\w.-]{0,50}?(?:confluent)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{16})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["confluent"] + +[[rules]] +id = "confluent-secret-key" +description = "Found a Confluent Secret Key, potentially risking unauthorized operations and data access within Confluent services." +regex = '''(?i)[\w.-]{0,50}?(?:confluent)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{64})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["confluent"] + +[[rules]] +id = "contentful-delivery-api-token" +description = "Discovered a Contentful delivery API token, posing a risk to content management systems and data integrity." +regex = '''(?i)[\w.-]{0,50}?(?:contentful)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9=_\-]{43})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["contentful"] + +[[rules]] +id = "curl-auth-header" +description = "Discovered a potential authorization token provided in a curl command header, which could compromise the curl accessed resource." +regex = '''\bcurl\b(?:.*?|.*?(?:[\r\n]{1,2}.*?){1,5})[ \t\n\r](?:-H|--header)(?:=|[ \t]{0,5})(?:"(?i)(?:Authorization:[ \t]{0,5}(?:Basic[ \t]([a-z0-9+/]{8,}={0,3})|(?:Bearer|(?:Api-)?Token)[ \t]([\w=~@.+/-]{8,})|([\w=~@.+/-]{8,}))|(?:(?:X-(?:[a-z]+-)?)?(?:Api-?)?(?:Key|Token)):[ \t]{0,5}([\w=~@.+/-]{8,}))"|'(?i)(?:Authorization:[ \t]{0,5}(?:Basic[ \t]([a-z0-9+/]{8,}={0,3})|(?:Bearer|(?:Api-)?Token)[ \t]([\w=~@.+/-]{8,})|([\w=~@.+/-]{8,}))|(?:(?:X-(?:[a-z]+-)?)?(?:Api-?)?(?:Key|Token)):[ \t]{0,5}([\w=~@.+/-]{8,}))')(?:\B|\s|\z)''' +entropy = 2.75 +keywords = ["curl"] + +[[rules]] +id = "curl-auth-user" +description = "Discovered a potential basic authorization token provided in a curl command, which could compromise the curl accessed resource." +regex = '''\bcurl\b(?:.*|.*(?:[\r\n]{1,2}.*){1,5})[ \t\n\r](?:-u|--user)(?:=|[ \t]{0,5})(?:"([^:"]{3,}:[^"]{3,})"|'([^:']{3,}:[^']{3,})'|((?:"[^"]{3,}"|'[^']{3,}'|[\w$@.-]+):(?:"[^"]{3,}"|'[^']{3,}'|[\w${}@.-]+)))(?:\s|\z)''' +entropy = 2 +keywords = ["curl"] +# NOTE: Gitleaks >= v8.21.0 should use [[rules.allowlists] instead. +[rules.allowlist] +regexes = [ + '''[^:]+:(change(it|me)|pass(word)?|pwd|test|token|\*+|x+)''', + '''['"]?<[^>]+>['"]?:['"]?<[^>]+>|<[^:]+:[^>]+>['"]?''', + '''[^:]+:\[[^]]+]''', + '''['"]?[^:]+['"]?:['"]?\$(\d|\w+|\{(\d|\w+)})['"]?''', + '''\$\([^)]+\):\$\([^)]+\)''', + '''['"]?\$?{{[^}]+}}['"]?:['"]?\$?{{[^}]+}}['"]?''', +] + +[[rules]] +id = "databricks-api-token" +description = "Uncovered a Databricks API token, which may compromise big data analytics platforms and sensitive data processing." +regex = '''\b(dapi[a-f0-9]{32}(?:-\d)?)(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 3 +keywords = ["dapi"] + +[[rules]] +id = "datadog-access-token" +description = "Detected a Datadog Access Token, potentially risking monitoring and analytics data exposure and manipulation." +regex = '''(?i)[\w.-]{0,50}?(?:datadog)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{40})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["datadog"] + +[[rules]] +id = "defined-networking-api-token" +description = "Identified a Defined Networking API token, which could lead to unauthorized network operations and data breaches." +regex = '''(?i)[\w.-]{0,50}?(?:dnkey)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}(dnkey-[a-z0-9=_\-]{26}-[a-z0-9=_\-]{52})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["dnkey"] + +[[rules]] +id = "digitalocean-access-token" +description = "Found a DigitalOcean OAuth Access Token, risking unauthorized cloud resource access and data compromise." +regex = '''\b(doo_v1_[a-f0-9]{64})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 3 +keywords = ["doo_v1_"] + +[[rules]] +id = "digitalocean-pat" +description = "Discovered a DigitalOcean Personal Access Token, posing a threat to cloud infrastructure security and data privacy." +regex = '''\b(dop_v1_[a-f0-9]{64})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 3 +keywords = ["dop_v1_"] + +[[rules]] +id = "digitalocean-refresh-token" +description = "Uncovered a DigitalOcean OAuth Refresh Token, which could allow prolonged unauthorized access and resource manipulation." +regex = '''(?i)\b(dor_v1_[a-f0-9]{64})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["dor_v1_"] + +[[rules]] +id = "discord-api-token" +description = "Detected a Discord API key, potentially compromising communication channels and user data privacy on Discord." +regex = '''(?i)[\w.-]{0,50}?(?:discord)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-f0-9]{64})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["discord"] + +[[rules]] +id = "discord-client-id" +description = "Identified a Discord client ID, which may lead to unauthorized integrations and data exposure in Discord applications." +regex = '''(?i)[\w.-]{0,50}?(?:discord)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([0-9]{18})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 2 +keywords = ["discord"] + +[[rules]] +id = "discord-client-secret" +description = "Discovered a potential Discord client secret, risking compromised Discord bot integrations and data leaks." +regex = '''(?i)[\w.-]{0,50}?(?:discord)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9=_\-]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 2 +keywords = ["discord"] + +[[rules]] +id = "doppler-api-token" +description = "Discovered a Doppler API token, posing a risk to environment and secrets management security." +regex = '''dp\.pt\.(?i)[a-z0-9]{43}''' +entropy = 2 +keywords = ["dp.pt."] + +[[rules]] +id = "droneci-access-token" +description = "Detected a Droneci Access Token, potentially compromising continuous integration and deployment workflows." +regex = '''(?i)[\w.-]{0,50}?(?:droneci)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["droneci"] + +[[rules]] +id = "dropbox-api-token" +description = "Identified a Dropbox API secret, which could lead to unauthorized file access and data breaches in Dropbox storage." +regex = '''(?i)[\w.-]{0,50}?(?:dropbox)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{15})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["dropbox"] + +[[rules]] +id = "dropbox-long-lived-api-token" +description = "Found a Dropbox long-lived API token, risking prolonged unauthorized access to cloud storage and sensitive data." +regex = '''(?i)[\w.-]{0,50}?(?:dropbox)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{11}(AAAAAAAAAA)[a-z0-9\-_=]{43})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["dropbox"] + +[[rules]] +id = "dropbox-short-lived-api-token" +description = "Discovered a Dropbox short-lived API token, posing a risk of temporary but potentially harmful data access and manipulation." +regex = '''(?i)[\w.-]{0,50}?(?:dropbox)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}(sl\.[a-z0-9\-=_]{135})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["dropbox"] + +[[rules]] +id = "duffel-api-token" +description = "Uncovered a Duffel API token, which may compromise travel platform integrations and sensitive customer data." +regex = '''duffel_(?:test|live)_(?i)[a-z0-9_\-=]{43}''' +entropy = 2 +keywords = ["duffel_"] + +[[rules]] +id = "dynatrace-api-token" +description = "Detected a Dynatrace API token, potentially risking application performance monitoring and data exposure." +regex = '''dt0c01\.(?i)[a-z0-9]{24}\.[a-z0-9]{64}''' +entropy = 4 +keywords = ["dt0c01"] + +[[rules]] +id = "easypost-api-token" +description = "Identified an EasyPost API token, which could lead to unauthorized postal and shipment service access and data exposure." +regex = '''\bEZAK(?i)[a-z0-9]{54}\b''' +entropy = 2 +keywords = ["ezak"] + +[[rules]] +id = "easypost-test-api-token" +description = "Detected an EasyPost test API token, risking exposure of test environments and potentially sensitive shipment data." +regex = '''\bEZTK(?i)[a-z0-9]{54}\b''' +entropy = 2 +keywords = ["eztk"] + +[[rules]] +id = "etsy-access-token" +description = "Found an Etsy Access Token, potentially compromising Etsy shop management and customer data." +regex = '''(?i)[\w.-]{0,50}?(?:(?-i:ETSY|[Ee]tsy))(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{24})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 3 +keywords = ["etsy"] + +[[rules]] +id = "facebook-access-token" +description = "Discovered a Facebook Access Token, posing a risk of unauthorized access to Facebook accounts and personal data exposure." +regex = '''(?i)\b(\d{15,16}(\||%)[0-9a-z\-_]{27,40})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 3 + +[[rules]] +id = "facebook-page-access-token" +description = "Discovered a Facebook Page Access Token, posing a risk of unauthorized access to Facebook accounts and personal data exposure." +regex = '''\b(EAA[MC](?i)[a-z0-9]{100,})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 4 +keywords = [ + "eaam", + "eaac", +] + +[[rules]] +id = "facebook-secret" +description = "Discovered a Facebook Application secret, posing a risk of unauthorized access to Facebook accounts and personal data exposure." +regex = '''(?i)[\w.-]{0,50}?(?:facebook)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-f0-9]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 3 +keywords = ["facebook"] + +[[rules]] +id = "fastly-api-token" +description = "Uncovered a Fastly API key, which may compromise CDN and edge cloud services, leading to content delivery and security issues." +regex = '''(?i)[\w.-]{0,50}?(?:fastly)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9=_\-]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["fastly"] + +[[rules]] +id = "finicity-api-token" +description = "Detected a Finicity API token, potentially risking financial data access and unauthorized financial operations." +regex = '''(?i)[\w.-]{0,50}?(?:finicity)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-f0-9]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["finicity"] + +[[rules]] +id = "finicity-client-secret" +description = "Identified a Finicity Client Secret, which could lead to compromised financial service integrations and data breaches." +regex = '''(?i)[\w.-]{0,50}?(?:finicity)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{20})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["finicity"] + +[[rules]] +id = "finnhub-access-token" +description = "Found a Finnhub Access Token, risking unauthorized access to financial market data and analytics." +regex = '''(?i)[\w.-]{0,50}?(?:finnhub)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{20})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["finnhub"] + +[[rules]] +id = "flickr-access-token" +description = "Discovered a Flickr Access Token, posing a risk of unauthorized photo management and potential data leakage." +regex = '''(?i)[\w.-]{0,50}?(?:flickr)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["flickr"] + +[[rules]] +id = "flutterwave-encryption-key" +description = "Uncovered a Flutterwave Encryption Key, which may compromise payment processing and sensitive financial information." +regex = '''FLWSECK_TEST-(?i)[a-h0-9]{12}''' +entropy = 2 +keywords = ["flwseck_test"] + +[[rules]] +id = "flutterwave-public-key" +description = "Detected a Finicity Public Key, potentially exposing public cryptographic operations and integrations." +regex = '''FLWPUBK_TEST-(?i)[a-h0-9]{32}-X''' +entropy = 2 +keywords = ["flwpubk_test"] + +[[rules]] +id = "flutterwave-secret-key" +description = "Identified a Flutterwave Secret Key, risking unauthorized financial transactions and data breaches." +regex = '''FLWSECK_TEST-(?i)[a-h0-9]{32}-X''' +entropy = 2 +keywords = ["flwseck_test"] + +[[rules]] +id = "flyio-access-token" +description = "Uncovered a Fly.io API key" +regex = '''\b((?:fo1_[\w-]{43}|fm1[ar]_[a-zA-Z0-9+\/]{100,}={0,3}|fm2_[a-zA-Z0-9+\/]{100,}={0,3}))(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 4 +keywords = [ + "fo1_", + "fm1", + "fm2_", +] + +[[rules]] +id = "frameio-api-token" +description = "Found a Frame.io API token, potentially compromising video collaboration and project management." +regex = '''fio-u-(?i)[a-z0-9\-_=]{64}''' +keywords = ["fio-u-"] + +[[rules]] +id = "freshbooks-access-token" +description = "Discovered a Freshbooks Access Token, posing a risk to accounting software access and sensitive financial data exposure." +regex = '''(?i)[\w.-]{0,50}?(?:freshbooks)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{64})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["freshbooks"] + +[[rules]] +id = "gcp-api-key" +description = "Uncovered a GCP API key, which could lead to unauthorized access to Google Cloud services and data breaches." +regex = '''\b(AIza[\w-]{35})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 3 +keywords = ["aiza"] + +[[rules]] +id = "generic-api-key" +description = "Detected a Generic API Key, potentially exposing access to various services and sensitive operations." +regex = '''(?i)[\w.-]{0,50}?(?:access|auth|(?-i:[Aa]pi|API)|credential|creds|key|passwd|password|secret|token)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([\w.=-]{10,150})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 3.5 +keywords = [ + "access", + "api", + "auth", + "key", + "credential", + "creds", + "passwd", + "password", + "secret", + "token", +] +# NOTE: Gitleaks >= v8.21.0 should use [[rules.allowlists] instead. +[rules.allowlist] +regexTarget = "match" +regexes = [ + '''(?i)(accessor|access[_.-]?id|api[_.-]?(version|id)|rapid|capital|[a-z0-9-]*?api[a-z0-9-]*?:jar:|author|X-MS-Exchange-Organization-Auth|Authentication-Results|(credentials?[_.-]?id|withCredentials)|(bucket|foreign|hot|natural|primary|schema|sequence)[_.-]?key|key[_.-]?(alias|board|code|ring|selector|size|stone|storetype|word|up|down|left|right)|key(store|tab)[_.-]?(file|path)|issuerkeyhash|(?-i:[DdMm]onkey|[DM]ONKEY)|keying|(secret)[_.-]?name|UserSecretsId|(api|credentials|token)[_.-]?(endpoint|ur[il])|public[_.-]?(key|token)|(key|token)[_.-]?file)''', +] +stopwords = [ + "000000", + "aaaaaa", + "about", + "abstract", + "academy", + "acces", + "account", + "act-", + "act.", + "act_", + "action", + "active", + "actively", + "activity", + "adapter", + "add-", + "add.", + "add_", + "add-on", + "addon", + "addres", + "admin", + "adobe", + "advanced", + "adventure", + "agent", + "agile", + "air-", + "air.", + "air_", + "ajax", + "akka", + "alert", + "alfred", + "algorithm", + "all-", + "all.", + "all_", + "alloy", + "alpha", + "amazon", + "amqp", + "analysi", + "analytic", + "analyzer", + "android", + "angular", + "angularj", + "animate", + "animation", + "another", + "ansible", + "answer", + "ant-", + "ant.", + "ant_", + "any-", + "any.", + "any_", + "apache", + "app-", + "app-", + "app.", + "app.", + "app_", + "app_", + "apple", + "arch", + "archive", + "archived", + "arduino", + "array", + "art-", + "art.", + "art_", + "article", + "asp-", + "asp.", + "asp_", + "asset", + "async", + "atom", + "attention", + "audio", + "audit", + "aura", + "auth", + "author", + "author", + "authorize", + "auto", + "automated", + "automatic", + "awesome", + "aws_", + "azure", + "back", + "backbone", + "backend", + "backup", + "bar-", + "bar.", + "bar_", + "base", + "based", + "bash", + "basic", + "batch", + "been", + "beer", + "behavior", + "being", + "benchmark", + "best", + "beta", + "better", + "big-", + "big.", + "big_", + "binary", + "binding", + "bit-", + "bit.", + "bit_", + "bitcoin", + "block", + "blog", + "board", + "book", + "bookmark", + "boost", + "boot", + "bootstrap", + "bosh", + "bot-", + "bot.", + "bot_", + "bower", + "box-", + "box.", + "box_", + "boxen", + "bracket", + "branch", + "bridge", + "browser", + "brunch", + "buffer", + "bug-", + "bug.", + "bug_", + "build", + "builder", + "building", + "buildout", + "buildpack", + "built", + "bundle", + "busines", + "but-", + "but.", + "but_", + "button", + "cache", + "caching", + "cakephp", + "calendar", + "call", + "camera", + "campfire", + "can-", + "can.", + "can_", + "canva", + "captcha", + "capture", + "card", + "carousel", + "case", + "cassandra", + "cat-", + "cat.", + "cat_", + "category", + "center", + "cento", + "challenge", + "change", + "changelog", + "channel", + "chart", + "chat", + "cheat", + "check", + "checker", + "chef", + "ches", + "chinese", + "chosen", + "chrome", + "ckeditor", + "clas", + "classe", + "classic", + "clean", + "cli-", + "cli.", + "cli_", + "client", + "client", + "clojure", + "clone", + "closure", + "cloud", + "club", + "cluster", + "cms-", + "cms_", + "coco", + "code", + "coding", + "coffee", + "color", + "combination", + "combo", + "command", + "commander", + "comment", + "commit", + "common", + "community", + "compas", + "compiler", + "complete", + "component", + "composer", + "computer", + "computing", + "con-", + "con.", + "con_", + "concept", + "conf", + "config", + "config", + "connect", + "connector", + "console", + "contact", + "container", + "contao", + "content", + "contest", + "context", + "control", + "convert", + "converter", + "conway'", + "cookbook", + "cookie", + "cool", + "copy", + "cordova", + "core", + "couchbase", + "couchdb", + "countdown", + "counter", + "course", + "craft", + "crawler", + "create", + "creating", + "creator", + "credential", + "crm-", + "crm.", + "crm_", + "cros", + "crud", + "csv-", + "csv.", + "csv_", + "cube", + "cucumber", + "cuda", + "current", + "currently", + "custom", + "daemon", + "dark", + "dart", + "dash", + "dashboard", + "data", + "database", + "date", + "day-", + "day.", + "day_", + "dead", + "debian", + "debug", + "debug", + "debugger", + "deck", + "define", + "del-", + "del.", + "del_", + "delete", + "demo", + "deploy", + "design", + "designer", + "desktop", + "detection", + "detector", + "dev-", + "dev.", + "dev_", + "develop", + "developer", + "device", + "devise", + "diff", + "digital", + "directive", + "directory", + "discovery", + "display", + "django", + "dns-", + "dns_", + "doc-", + "doc-", + "doc.", + "doc.", + "doc_", + "doc_", + "docker", + "docpad", + "doctrine", + "document", + "doe-", + "doe.", + "doe_", + "dojo", + "dom-", + "dom.", + "dom_", + "domain", + "done", + "don't", + "dot-", + "dot.", + "dot_", + "dotfile", + "download", + "draft", + "drag", + "drill", + "drive", + "driven", + "driver", + "drop", + "dropbox", + "drupal", + "dsl-", + "dsl.", + "dsl_", + "dynamic", + "easy", + "_ec2_", + "ecdsa", + "eclipse", + "edit", + "editing", + "edition", + "editor", + "element", + "emac", + "email", + "embed", + "embedded", + "ember", + "emitter", + "emulator", + "encoding", + "endpoint", + "engine", + "english", + "enhanced", + "entity", + "entry", + "env_", + "episode", + "erlang", + "error", + "espresso", + "event", + "evented", + "example", + "example", + "exchange", + "exercise", + "experiment", + "expire", + "exploit", + "explorer", + "export", + "exporter", + "expres", + "ext-", + "ext.", + "ext_", + "extended", + "extension", + "external", + "extra", + "extractor", + "fabric", + "facebook", + "factory", + "fake", + "fast", + "feature", + "feed", + "fewfwef", + "ffmpeg", + "field", + "file", + "filter", + "find", + "finder", + "firefox", + "firmware", + "first", + "fish", + "fix-", + "fix_", + "flash", + "flask", + "flat", + "flex", + "flexible", + "flickr", + "flow", + "fluent", + "fluentd", + "fluid", + "folder", + "font", + "force", + "foreman", + "fork", + "form", + "format", + "formatter", + "forum", + "foundry", + "framework", + "free", + "friend", + "friendly", + "front-end", + "frontend", + "ftp-", + "ftp.", + "ftp_", + "fuel", + "full", + "fun-", + "fun.", + "fun_", + "func", + "future", + "gaia", + "gallery", + "game", + "gateway", + "gem-", + "gem.", + "gem_", + "gen-", + "gen.", + "gen_", + "general", + "generator", + "generic", + "genetic", + "get-", + "get.", + "get_", + "getenv", + "getting", + "ghost", + "gist", + "git-", + "git.", + "git_", + "github", + "gitignore", + "gitlab", + "glas", + "gmail", + "gnome", + "gnu-", + "gnu.", + "gnu_", + "goal", + "golang", + "gollum", + "good", + "google", + "gpu-", + "gpu.", + "gpu_", + "gradle", + "grail", + "graph", + "graphic", + "great", + "grid", + "groovy", + "group", + "grunt", + "guard", + "gui-", + "gui.", + "gui_", + "guide", + "guideline", + "gulp", + "gwt-", + "gwt.", + "gwt_", + "hack", + "hackathon", + "hacker", + "hacking", + "hadoop", + "haml", + "handler", + "hardware", + "has-", + "has_", + "hash", + "haskell", + "have", + "haxe", + "hello", + "help", + "helper", + "here", + "hero", + "heroku", + "high", + "hipchat", + "history", + "home", + "homebrew", + "homepage", + "hook", + "host", + "hosting", + "hot-", + "hot.", + "hot_", + "house", + "how-", + "how.", + "how_", + "html", + "http", + "hub-", + "hub.", + "hub_", + "hubot", + "human", + "icon", + "ide-", + "ide.", + "ide_", + "idea", + "identity", + "idiomatic", + "image", + "impact", + "import", + "important", + "importer", + "impres", + "index", + "infinite", + "info", + "injection", + "inline", + "input", + "inside", + "inspector", + "instagram", + "install", + "installer", + "instant", + "intellij", + "interface", + "internet", + "interview", + "into", + "intro", + "ionic", + "iphone", + "ipython", + "irc-", + "irc_", + "iso-", + "iso.", + "iso_", + "issue", + "jade", + "jasmine", + "java", + "jbos", + "jekyll", + "jenkin", + "jetbrains", + "job-", + "job.", + "job_", + "joomla", + "jpa-", + "jpa.", + "jpa_", + "jquery", + "json", + "just", + "kafka", + "karma", + "kata", + "kernel", + "keyboard", + "kindle", + "kit-", + "kit.", + "kit_", + "kitchen", + "knife", + "koan", + "kohana", + "lab-", + "lab-", + "lab.", + "lab.", + "lab_", + "lab_", + "lambda", + "lamp", + "language", + "laravel", + "last", + "latest", + "latex", + "launcher", + "layer", + "layout", + "lazy", + "ldap", + "leaflet", + "league", + "learn", + "learning", + "led-", + "led.", + "led_", + "leetcode", + "les-", + "les.", + "les_", + "level", + "leveldb", + "lib-", + "lib.", + "lib_", + "librarie", + "library", + "license", + "life", + "liferay", + "light", + "lightbox", + "like", + "line", + "link", + "linked", + "linkedin", + "linux", + "lisp", + "list", + "lite", + "little", + "load", + "loader", + "local", + "location", + "lock", + "log-", + "log.", + "log_", + "logger", + "logging", + "logic", + "login", + "logstash", + "longer", + "look", + "love", + "lua-", + "lua.", + "lua_", + "mac-", + "mac.", + "mac_", + "machine", + "made", + "magento", + "magic", + "mail", + "make", + "maker", + "making", + "man-", + "man.", + "man_", + "manage", + "manager", + "manifest", + "manual", + "map-", + "map-", + "map.", + "map.", + "map_", + "map_", + "mapper", + "mapping", + "markdown", + "markup", + "master", + "math", + "matrix", + "maven", + "md5", + "mean", + "media", + "mediawiki", + "meetup", + "memcached", + "memory", + "menu", + "merchant", + "message", + "messaging", + "meta", + "metadata", + "meteor", + "method", + "metric", + "micro", + "middleman", + "migration", + "minecraft", + "miner", + "mini", + "minimal", + "mirror", + "mit-", + "mit.", + "mit_", + "mobile", + "mocha", + "mock", + "mod-", + "mod.", + "mod_", + "mode", + "model", + "modern", + "modular", + "module", + "modx", + "money", + "mongo", + "mongodb", + "mongoid", + "mongoose", + "monitor", + "monkey", + "more", + "motion", + "moved", + "movie", + "mozilla", + "mqtt", + "mule", + "multi", + "multiple", + "music", + "mustache", + "mvc-", + "mvc.", + "mvc_", + "mysql", + "nagio", + "name", + "native", + "need", + "neo-", + "neo.", + "neo_", + "nest", + "nested", + "net-", + "net.", + "net_", + "nette", + "network", + "new-", + "new-", + "new.", + "new.", + "new_", + "new_", + "next", + "nginx", + "ninja", + "nlp-", + "nlp.", + "nlp_", + "node", + "nodej", + "nosql", + "not-", + "not.", + "not_", + "note", + "notebook", + "notepad", + "notice", + "notifier", + "now-", + "now.", + "now_", + "number", + "oauth", + "object", + "objective", + "obsolete", + "ocaml", + "octopres", + "official", + "old-", + "old.", + "old_", + "onboard", + "online", + "only", + "open", + "opencv", + "opengl", + "openshift", + "openwrt", + "option", + "oracle", + "org-", + "org.", + "org_", + "origin", + "original", + "orm-", + "orm.", + "orm_", + "osx-", + "osx_", + "our-", + "our.", + "our_", + "out-", + "out.", + "out_", + "output", + "over", + "overview", + "own-", + "own.", + "own_", + "pack", + "package", + "packet", + "page", + "page", + "panel", + "paper", + "paperclip", + "para", + "parallax", + "parallel", + "parse", + "parser", + "parsing", + "particle", + "party", + "password", + "patch", + "path", + "pattern", + "payment", + "paypal", + "pdf-", + "pdf.", + "pdf_", + "pebble", + "people", + "perl", + "personal", + "phalcon", + "phoenix", + "phone", + "phonegap", + "photo", + "php-", + "php.", + "php_", + "physic", + "picker", + "pipeline", + "platform", + "play", + "player", + "please", + "plu-", + "plu.", + "plu_", + "plug-in", + "plugin", + "plupload", + "png-", + "png.", + "png_", + "poker", + "polyfill", + "polymer", + "pool", + "pop-", + "pop.", + "pop_", + "popcorn", + "popup", + "port", + "portable", + "portal", + "portfolio", + "post", + "power", + "powered", + "powerful", + "prelude", + "pretty", + "preview", + "principle", + "print", + "pro-", + "pro.", + "pro_", + "problem", + "proc", + "product", + "profile", + "profiler", + "program", + "progres", + "project", + "protocol", + "prototype", + "provider", + "proxy", + "public", + "pull", + "puppet", + "pure", + "purpose", + "push", + "pusher", + "pyramid", + "python", + "quality", + "query", + "queue", + "quick", + "rabbitmq", + "rack", + "radio", + "rail", + "railscast", + "random", + "range", + "raspberry", + "rdf-", + "rdf.", + "rdf_", + "react", + "reactive", + "read", + "reader", + "readme", + "ready", + "real", + "reality", + "real-time", + "realtime", + "recipe", + "recorder", + "red-", + "red.", + "red_", + "reddit", + "redi", + "redmine", + "reference", + "refinery", + "refresh", + "registry", + "related", + "release", + "remote", + "rendering", + "repo", + "report", + "request", + "require", + "required", + "requirej", + "research", + "resource", + "response", + "resque", + "rest", + "restful", + "resume", + "reveal", + "reverse", + "review", + "riak", + "rich", + "right", + "ring", + "robot", + "role", + "room", + "router", + "routing", + "rpc-", + "rpc.", + "rpc_", + "rpg-", + "rpg.", + "rpg_", + "rspec", + "ruby-", + "ruby.", + "ruby_", + "rule", + "run-", + "run.", + "run_", + "runner", + "running", + "runtime", + "rust", + "rvm-", + "rvm.", + "rvm_", + "salt", + "sample", + "sample", + "sandbox", + "sas-", + "sas.", + "sas_", + "sbt-", + "sbt.", + "sbt_", + "scala", + "scalable", + "scanner", + "schema", + "scheme", + "school", + "science", + "scraper", + "scratch", + "screen", + "script", + "scroll", + "scs-", + "scs.", + "scs_", + "sdk-", + "sdk.", + "sdk_", + "sdl-", + "sdl.", + "sdl_", + "search", + "secure", + "security", + "see-", + "see.", + "see_", + "seed", + "select", + "selector", + "selenium", + "semantic", + "sencha", + "send", + "sentiment", + "serie", + "server", + "service", + "session", + "set-", + "set.", + "set_", + "setting", + "setting", + "setup", + "sha1", + "sha2", + "sha256", + "share", + "shared", + "sharing", + "sheet", + "shell", + "shield", + "shipping", + "shop", + "shopify", + "shortener", + "should", + "show", + "showcase", + "side", + "silex", + "simple", + "simulator", + "single", + "site", + "skeleton", + "sketch", + "skin", + "slack", + "slide", + "slider", + "slim", + "small", + "smart", + "smtp", + "snake", + "snapshot", + "snippet", + "soap", + "social", + "socket", + "software", + "solarized", + "solr", + "solution", + "solver", + "some", + "soon", + "source", + "space", + "spark", + "spatial", + "spec", + "sphinx", + "spine", + "spotify", + "spree", + "spring", + "sprite", + "sql-", + "sql.", + "sql_", + "sqlite", + "ssh-", + "ssh.", + "ssh_", + "stack", + "staging", + "standard", + "stanford", + "start", + "started", + "starter", + "startup", + "stat", + "statamic", + "state", + "static", + "statistic", + "statsd", + "statu", + "steam", + "step", + "still", + "stm-", + "stm.", + "stm_", + "storage", + "store", + "storm", + "story", + "strategy", + "stream", + "streaming", + "string", + "stripe", + "structure", + "studio", + "study", + "stuff", + "style", + "sublime", + "sugar", + "suite", + "summary", + "super", + "support", + "supported", + "svg-", + "svg.", + "svg_", + "svn-", + "svn.", + "svn_", + "swagger", + "swift", + "switch", + "switcher", + "symfony", + "symphony", + "sync", + "synopsi", + "syntax", + "system", + "system", + "tab-", + "tab-", + "tab.", + "tab.", + "tab_", + "tab_", + "table", + "tag-", + "tag-", + "tag.", + "tag.", + "tag_", + "tag_", + "talk", + "target", + "task", + "tcp-", + "tcp.", + "tcp_", + "tdd-", + "tdd.", + "tdd_", + "team", + "tech", + "template", + "term", + "terminal", + "testing", + "tetri", + "text", + "textmate", + "theme", + "theory", + "three", + "thrift", + "time", + "timeline", + "timer", + "tiny", + "tinymce", + "tip-", + "tip.", + "tip_", + "title", + "todo", + "todomvc", + "token", + "tool", + "toolbox", + "toolkit", + "top-", + "top.", + "top_", + "tornado", + "touch", + "tower", + "tracker", + "tracking", + "traffic", + "training", + "transfer", + "translate", + "transport", + "tree", + "trello", + "try-", + "try.", + "try_", + "tumblr", + "tut-", + "tut.", + "tut_", + "tutorial", + "tweet", + "twig", + "twitter", + "type", + "typo", + "ubuntu", + "uiview", + "ultimate", + "under", + "unit", + "unity", + "universal", + "unix", + "update", + "updated", + "upgrade", + "upload", + "uploader", + "uri-", + "uri.", + "uri_", + "url-", + "url.", + "url_", + "usage", + "usb-", + "usb.", + "usb_", + "use-", + "use.", + "use_", + "used", + "useful", + "user", + "using", + "util", + "utilitie", + "utility", + "vagrant", + "validator", + "value", + "variou", + "varnish", + "version", + "via-", + "via.", + "via_", + "video", + "view", + "viewer", + "vim-", + "vim.", + "vim_", + "vimrc", + "virtual", + "vision", + "visual", + "vpn", + "want", + "warning", + "watch", + "watcher", + "wave", + "way-", + "way.", + "way_", + "weather", + "web-", + "web_", + "webapp", + "webgl", + "webhook", + "webkit", + "webrtc", + "website", + "websocket", + "welcome", + "welcome", + "what", + "what'", + "when", + "where", + "which", + "why-", + "why.", + "why_", + "widget", + "wifi", + "wiki", + "win-", + "win.", + "win_", + "window", + "wip-", + "wip.", + "wip_", + "within", + "without", + "wizard", + "word", + "wordpres", + "work", + "worker", + "workflow", + "working", + "workshop", + "world", + "wrapper", + "write", + "writer", + "writing", + "written", + "www-", + "www.", + "www_", + "xamarin", + "xcode", + "xml-", + "xml.", + "xml_", + "xmpp", + "xxxxxx", + "yahoo", + "yaml", + "yandex", + "yeoman", + "yet-", + "yet.", + "yet_", + "yii-", + "yii.", + "yii_", + "youtube", + "yui-", + "yui.", + "yui_", + "zend", + "zero", + "zip-", + "zip.", + "zip_", + "zsh-", + "zsh.", + "zsh_", +] + +[[rules]] +id = "github-app-token" +description = "Identified a GitHub App Token, which may compromise GitHub application integrations and source code security." +regex = '''(?:ghu|ghs)_[0-9a-zA-Z]{36}''' +entropy = 3 +keywords = [ + "ghu_", + "ghs_", +] +# NOTE: Gitleaks >= v8.21.0 should use [[rules.allowlists] instead. +[rules.allowlist] +paths = [ + '''(^|/)@octokit/auth-token/README\.md$''', +] + +[[rules]] +id = "github-fine-grained-pat" +description = "Found a GitHub Fine-Grained Personal Access Token, risking unauthorized repository access and code manipulation." +regex = '''github_pat_\w{82}''' +entropy = 3 +keywords = ["github_pat_"] + +[[rules]] +id = "github-oauth" +description = "Discovered a GitHub OAuth Access Token, posing a risk of compromised GitHub account integrations and data leaks." +regex = '''gho_[0-9a-zA-Z]{36}''' +entropy = 3 +keywords = ["gho_"] + +[[rules]] +id = "github-pat" +description = "Uncovered a GitHub Personal Access Token, potentially leading to unauthorized repository access and sensitive content exposure." +regex = '''ghp_[0-9a-zA-Z]{36}''' +entropy = 3 +keywords = ["ghp_"] +# NOTE: Gitleaks >= v8.21.0 should use [[rules.allowlists] instead. +[rules.allowlist] +paths = [ + '''(^|/)@octokit/auth-token/README\.md$''', +] + +[[rules]] +id = "github-refresh-token" +description = "Detected a GitHub Refresh Token, which could allow prolonged unauthorized access to GitHub services." +regex = '''ghr_[0-9a-zA-Z]{36}''' +entropy = 3 +keywords = ["ghr_"] + +[[rules]] +id = "gitlab-cicd-job-token" +description = "Identified a GitLab CI/CD Job Token, potential access to projects and some APIs on behalf of a user while the CI job is running." +regex = '''glcbt-[0-9a-zA-Z]{1,5}_[0-9a-zA-Z_-]{20}''' +entropy = 3 +keywords = ["glcbt-"] + +[[rules]] +id = "gitlab-deploy-token" +description = "Identified a GitLab Deploy Token, risking access to repositories, packages and containers with write access." +regex = '''gldt-[0-9a-zA-Z_\-]{20}''' +entropy = 3 +keywords = ["gldt-"] + +[[rules]] +id = "gitlab-feature-flag-client-token" +description = "Identified a GitLab feature flag client token, risks exposing user lists and features flags used by an application." +regex = '''glffct-[0-9a-zA-Z_\-]{20}''' +entropy = 3 +keywords = ["glffct-"] + +[[rules]] +id = "gitlab-feed-token" +description = "Identified a GitLab feed token, risking exposure of user data." +regex = '''glft-[0-9a-zA-Z_\-]{20}''' +entropy = 3 +keywords = ["glft-"] + +[[rules]] +id = "gitlab-incoming-mail-token" +description = "Identified a GitLab incoming mail token, risking manipulation of data sent by mail." +regex = '''glimt-[0-9a-zA-Z_\-]{25}''' +entropy = 3 +keywords = ["glimt-"] + +[[rules]] +id = "gitlab-kubernetes-agent-token" +description = "Identified a GitLab Kubernetes Agent token, risking access to repos and registry of projects connected via agent." +regex = '''glagent-[0-9a-zA-Z_\-]{50}''' +entropy = 3 +keywords = ["glagent-"] + +[[rules]] +id = "gitlab-oauth-app-secret" +description = "Identified a GitLab OIDC Application Secret, risking access to apps using GitLab as authentication provider." +regex = '''gloas-[0-9a-zA-Z_\-]{64}''' +entropy = 3 +keywords = ["gloas-"] + +[[rules]] +id = "gitlab-pat" +description = "Identified a GitLab Personal Access Token, risking unauthorized access to GitLab repositories and codebase exposure." +regex = '''glpat-[\w-]{20}''' +entropy = 3 +keywords = ["glpat-"] + +[[rules]] +id = "gitlab-ptt" +description = "Found a GitLab Pipeline Trigger Token, potentially compromising continuous integration workflows and project security." +regex = '''glptt-[0-9a-f]{40}''' +entropy = 3 +keywords = ["glptt-"] + +[[rules]] +id = "gitlab-rrt" +description = "Discovered a GitLab Runner Registration Token, posing a risk to CI/CD pipeline integrity and unauthorized access." +regex = '''GR1348941[\w-]{20}''' +entropy = 3 +keywords = ["gr1348941"] + +[[rules]] +id = "gitlab-runner-authentication-token" +description = "Discovered a GitLab Runner Authentication Token, posing a risk to CI/CD pipeline integrity and unauthorized access." +regex = '''glrt-[0-9a-zA-Z_\-]{20}''' +entropy = 3 +keywords = ["glrt-"] + +[[rules]] +id = "gitlab-scim-token" +description = "Discovered a GitLab SCIM Token, posing a risk to unauthorized access for a organization or instance." +regex = '''glsoat-[0-9a-zA-Z_\-]{20}''' +entropy = 3 +keywords = ["glsoat-"] + +[[rules]] +id = "gitlab-session-cookie" +description = "Discovered a GitLab Session Cookie, posing a risk to unauthorized access to a user account." +regex = '''_gitlab_session=[0-9a-z]{32}''' +entropy = 3 +keywords = ["_gitlab_session="] + +[[rules]] +id = "gitter-access-token" +description = "Uncovered a Gitter Access Token, which may lead to unauthorized access to chat and communication services." +regex = '''(?i)[\w.-]{0,50}?(?:gitter)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9_-]{40})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["gitter"] + +[[rules]] +id = "gocardless-api-token" +description = "Detected a GoCardless API token, potentially risking unauthorized direct debit payment operations and financial data exposure." +regex = '''(?i)[\w.-]{0,50}?(?:gocardless)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}(live_(?i)[a-z0-9\-_=]{40})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = [ + "live_", + "gocardless", +] + +[[rules]] +id = "grafana-api-key" +description = "Identified a Grafana API key, which could compromise monitoring dashboards and sensitive data analytics." +regex = '''(?i)\b(eyJrIjoi[A-Za-z0-9]{70,400}={0,3})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 3 +keywords = ["eyjrijoi"] + +[[rules]] +id = "grafana-cloud-api-token" +description = "Found a Grafana cloud API token, risking unauthorized access to cloud-based monitoring services and data exposure." +regex = '''(?i)\b(glc_[A-Za-z0-9+/]{32,400}={0,3})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 3 +keywords = ["glc_"] + +[[rules]] +id = "grafana-service-account-token" +description = "Discovered a Grafana service account token, posing a risk of compromised monitoring services and data integrity." +regex = '''(?i)\b(glsa_[A-Za-z0-9]{32}_[A-Fa-f0-9]{8})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 3 +keywords = ["glsa_"] + +[[rules]] +id = "harness-api-key" +description = "Identified a Harness Access Token (PAT or SAT), risking unauthorized access to a Harness account." +regex = '''(?:pat|sat)\.[a-zA-Z0-9_-]{22}\.[a-zA-Z0-9]{24}\.[a-zA-Z0-9]{20}''' +keywords = [ + "pat.", + "sat.", +] + +[[rules]] +id = "hashicorp-tf-api-token" +description = "Uncovered a HashiCorp Terraform user/org API token, which may lead to unauthorized infrastructure management and security breaches." +regex = '''(?i)[a-z0-9]{14}\.(?-i:atlasv1)\.[a-z0-9\-_=]{60,70}''' +entropy = 3.5 +keywords = ["atlasv1"] + +[[rules]] +id = "hashicorp-tf-password" +description = "Identified a HashiCorp Terraform password field, risking unauthorized infrastructure configuration and security breaches." +regex = '''(?i)[\w.-]{0,50}?(?:administrator_login_password|password)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}("[a-z0-9=_\-]{8,20}")(?:['|\"|\n|\r|\s|\x60|;]|$)''' +path = '''(?i)\.(?:tf|hcl)$''' +entropy = 2 +keywords = [ + "administrator_login_password", + "password", +] + +[[rules]] +id = "heroku-api-key" +description = "Detected a Heroku API Key, potentially compromising cloud application deployments and operational security." +regex = '''(?i)[\w.-]{0,50}?(?:heroku)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["heroku"] + +[[rules]] +id = "hubspot-api-key" +description = "Found a HubSpot API Token, posing a risk to CRM data integrity and unauthorized marketing operations." +regex = '''(?i)[\w.-]{0,50}?(?:hubspot)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["hubspot"] + +[[rules]] +id = "huggingface-access-token" +description = "Discovered a Hugging Face Access token, which could lead to unauthorized access to AI models and sensitive data." +regex = '''\b(hf_(?i:[a-z]{34}))(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 2 +keywords = ["hf_"] + +[[rules]] +id = "huggingface-organization-api-token" +description = "Uncovered a Hugging Face Organization API token, potentially compromising AI organization accounts and associated data." +regex = '''\b(api_org_(?i:[a-z]{34}))(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 2 +keywords = ["api_org_"] + +[[rules]] +id = "infracost-api-token" +description = "Detected an Infracost API Token, risking unauthorized access to cloud cost estimation tools and financial data." +regex = '''\b(ico-[a-zA-Z0-9]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 3 +keywords = ["ico-"] + +[[rules]] +id = "intercom-api-key" +description = "Identified an Intercom API Token, which could compromise customer communication channels and data privacy." +regex = '''(?i)[\w.-]{0,50}?(?:intercom)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9=_\-]{60})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["intercom"] + +[[rules]] +id = "intra42-client-secret" +description = "Found a Intra42 client secret, which could lead to unauthorized access to the 42School API and sensitive data." +regex = '''\b(s-s4t2(?:ud|af)-(?i)[abcdef0123456789]{64})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 3 +keywords = [ + "intra", + "s-s4t2ud-", + "s-s4t2af-", +] + +[[rules]] +id = "jfrog-api-key" +description = "Found a JFrog API Key, posing a risk of unauthorized access to software artifact repositories and build pipelines." +regex = '''(?i)[\w.-]{0,50}?(?:jfrog|artifactory|bintray|xray)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{73})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = [ + "jfrog", + "artifactory", + "bintray", + "xray", +] + +[[rules]] +id = "jfrog-identity-token" +description = "Discovered a JFrog Identity Token, potentially compromising access to JFrog services and sensitive software artifacts." +regex = '''(?i)[\w.-]{0,50}?(?:jfrog|artifactory|bintray|xray)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{64})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = [ + "jfrog", + "artifactory", + "bintray", + "xray", +] + +[[rules]] +id = "jwt" +description = "Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data." +regex = '''\b(ey[a-zA-Z0-9]{17,}\.ey[a-zA-Z0-9\/\\_-]{17,}\.(?:[a-zA-Z0-9\/\\_-]{10,}={0,2})?)(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 3 +keywords = ["ey"] + +[[rules]] +id = "jwt-base64" +description = "Detected a Base64-encoded JSON Web Token, posing a risk of exposing encoded authentication and data exchange information." +regex = '''\bZXlK(?:(?PaGJHY2lPaU)|(?PaGNIVWlPaU)|(?PaGNIWWlPaU)|(?PaGRXUWlPaU)|(?PaU5qUWlP)|(?PamNtbDBJanBi)|(?PamRIa2lPaU)|(?PbGNHc2lPbn)|(?PbGJtTWlPaU)|(?PcWEzVWlPaU)|(?PcWQyc2lPb)|(?PcGMzTWlPaU)|(?PcGRpSTZJ)|(?PcmFXUWlP)|(?PclpYbGZiM0J6SWpwY)|(?PcmRIa2lPaUp)|(?PdWIyNWpaU0k2)|(?Pd01tTWlP)|(?Pd01uTWlPaU)|(?Pd2NIUWlPaU)|(?PemRXSWlPaU)|(?PemRuUWlP)|(?PMFlXY2lPaU)|(?PMGVYQWlPaUp)|(?PMWNtd2l)|(?PMWMyVWlPaUp)|(?PMlpYSWlPaU)|(?PMlpYSnphVzl1SWpv)|(?PNElqb2)|(?PNE5XTWlP)|(?PNE5YUWlPaU)|(?PNE5YUWpVekkxTmlJNkl)|(?PNE5YVWlPaU)|(?PNmFYQWlPaU))[a-zA-Z0-9\/\\_+\-\r\n]{40,}={0,2}''' +entropy = 2 +keywords = ["zxlk"] + +[[rules]] +id = "kraken-access-token" +description = "Identified a Kraken Access Token, potentially compromising cryptocurrency trading accounts and financial security." +regex = '''(?i)[\w.-]{0,50}?(?:kraken)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9\/=_\+\-]{80,90})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["kraken"] + +[[rules]] +id = "kubernetes-secret-yaml" +description = "Possible Kubernetes Secret detected, posing a risk of leaking credentials/tokens from your deployments" +regex = '''(?i)(?:\bkind:[ \t]*["']?secret["']?(?:.|\s){0,200}?\bdata:(?:.|\s){0,100}?\s+([\w.-]+:(?:[ \t]*(?:\||>[-+]?)\s+)?[ \t]*(?:["']?[a-z0-9+/]{10,}={0,3}["']?|\{\{[ \t\w"|$:=,.-]+}}|""|''))|\bdata:(?:.|\s){0,100}?\s+([\w.-]+:(?:[ \t]*(?:\||>[-+]?)\s+)?[ \t]*(?:["']?[a-z0-9+/]{10,}={0,3}["']?|\{\{[ \t\w"|$:=,.-]+}}|""|''))(?:.|\s){0,200}?\bkind:[ \t]*["']?secret["']?)''' +path = '''(?i)\.ya?ml$''' +keywords = ["secret"] +# NOTE: Gitleaks >= v8.21.0 should use [[rules.allowlists] instead. +[rules.allowlist] +regexes = [ + '''[\w.-]+:(?:[ \t]*(?:\||>[-+]?)\s+)?[ \t]*(?:\{\{[ \t\w"|$:=,.-]+}}|""|'')''', +] + +[[rules]] +id = "kucoin-access-token" +description = "Found a Kucoin Access Token, risking unauthorized access to cryptocurrency exchange services and transactions." +regex = '''(?i)[\w.-]{0,50}?(?:kucoin)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-f0-9]{24})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["kucoin"] + +[[rules]] +id = "kucoin-secret-key" +description = "Discovered a Kucoin Secret Key, which could lead to compromised cryptocurrency operations and financial data breaches." +regex = '''(?i)[\w.-]{0,50}?(?:kucoin)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["kucoin"] + +[[rules]] +id = "launchdarkly-access-token" +description = "Uncovered a Launchdarkly Access Token, potentially compromising feature flag management and application functionality." +regex = '''(?i)[\w.-]{0,50}?(?:launchdarkly)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9=_\-]{40})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["launchdarkly"] + +[[rules]] +id = "linear-api-key" +description = "Detected a Linear API Token, posing a risk to project management tools and sensitive task data." +regex = '''lin_api_(?i)[a-z0-9]{40}''' +entropy = 2 +keywords = ["lin_api_"] + +[[rules]] +id = "linear-client-secret" +description = "Identified a Linear Client Secret, which may compromise secure integrations and sensitive project management data." +regex = '''(?i)[\w.-]{0,50}?(?:linear)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-f0-9]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 2 +keywords = ["linear"] + +[[rules]] +id = "linkedin-client-id" +description = "Found a LinkedIn Client ID, risking unauthorized access to LinkedIn integrations and professional data exposure." +regex = '''(?i)[\w.-]{0,50}?(?:linked[_-]?in)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{14})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 2 +keywords = [ + "linkedin", + "linked_in", + "linked-in", +] + +[[rules]] +id = "linkedin-client-secret" +description = "Discovered a LinkedIn Client secret, potentially compromising LinkedIn application integrations and user data." +regex = '''(?i)[\w.-]{0,50}?(?:linked[_-]?in)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{16})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 2 +keywords = [ + "linkedin", + "linked_in", + "linked-in", +] + +[[rules]] +id = "lob-api-key" +description = "Uncovered a Lob API Key, which could lead to unauthorized access to mailing and address verification services." +regex = '''(?i)[\w.-]{0,50}?(?:lob)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}((live|test)_[a-f0-9]{35})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = [ + "test_", + "live_", +] + +[[rules]] +id = "lob-pub-api-key" +description = "Detected a Lob Publishable API Key, posing a risk of exposing mail and print service integrations." +regex = '''(?i)[\w.-]{0,50}?(?:lob)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}((test|live)_pub_[a-f0-9]{31})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = [ + "test_pub", + "live_pub", + "_pub", +] + +[[rules]] +id = "mailchimp-api-key" +description = "Identified a Mailchimp API key, potentially compromising email marketing campaigns and subscriber data." +regex = '''(?i)[\w.-]{0,50}?(?:MailchimpSDK.initialize|mailchimp)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-f0-9]{32}-us\d\d)(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["mailchimp"] + +[[rules]] +id = "mailgun-private-api-token" +description = "Found a Mailgun private API token, risking unauthorized email service operations and data breaches." +regex = '''(?i)[\w.-]{0,50}?(?:mailgun)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}(key-[a-f0-9]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["mailgun"] + +[[rules]] +id = "mailgun-pub-key" +description = "Discovered a Mailgun public validation key, which could expose email verification processes and associated data." +regex = '''(?i)[\w.-]{0,50}?(?:mailgun)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}(pubkey-[a-f0-9]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["mailgun"] + +[[rules]] +id = "mailgun-signing-key" +description = "Uncovered a Mailgun webhook signing key, potentially compromising email automation and data integrity." +regex = '''(?i)[\w.-]{0,50}?(?:mailgun)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-h0-9]{32}-[a-h0-9]{8}-[a-h0-9]{8})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["mailgun"] + +[[rules]] +id = "mapbox-api-token" +description = "Detected a MapBox API token, posing a risk to geospatial services and sensitive location data exposure." +regex = '''(?i)[\w.-]{0,50}?(?:mapbox)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}(pk\.[a-z0-9]{60}\.[a-z0-9]{22})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["mapbox"] + +[[rules]] +id = "mattermost-access-token" +description = "Identified a Mattermost Access Token, which may compromise team communication channels and data privacy." +regex = '''(?i)[\w.-]{0,50}?(?:mattermost)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{26})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["mattermost"] + +[[rules]] +id = "messagebird-api-token" +description = "Found a MessageBird API token, risking unauthorized access to communication platforms and message data." +regex = '''(?i)[\w.-]{0,50}?(?:message[_-]?bird)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{25})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = [ + "messagebird", + "message-bird", + "message_bird", +] + +[[rules]] +id = "messagebird-client-id" +description = "Discovered a MessageBird client ID, potentially compromising API integrations and sensitive communication data." +regex = '''(?i)[\w.-]{0,50}?(?:message[_-]?bird)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = [ + "messagebird", + "message-bird", + "message_bird", +] + +[[rules]] +id = "microsoft-teams-webhook" +description = "Uncovered a Microsoft Teams Webhook, which could lead to unauthorized access to team collaboration tools and data leaks." +regex = '''https://[a-z0-9]+\.webhook\.office\.com/webhookb2/[a-z0-9]{8}-([a-z0-9]{4}-){3}[a-z0-9]{12}@[a-z0-9]{8}-([a-z0-9]{4}-){3}[a-z0-9]{12}/IncomingWebhook/[a-z0-9]{32}/[a-z0-9]{8}-([a-z0-9]{4}-){3}[a-z0-9]{12}''' +keywords = [ + "webhook.office.com", + "webhookb2", + "incomingwebhook", +] + +[[rules]] +id = "netlify-access-token" +description = "Detected a Netlify Access Token, potentially compromising web hosting services and site management." +regex = '''(?i)[\w.-]{0,50}?(?:netlify)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9=_\-]{40,46})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["netlify"] + +[[rules]] +id = "new-relic-browser-api-token" +description = "Identified a New Relic ingest browser API token, risking unauthorized access to application performance data and analytics." +regex = '''(?i)[\w.-]{0,50}?(?:new-relic|newrelic|new_relic)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}(NRJS-[a-f0-9]{19})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["nrjs-"] + +[[rules]] +id = "new-relic-insert-key" +description = "Discovered a New Relic insight insert key, compromising data injection into the platform." +regex = '''(?i)[\w.-]{0,50}?(?:new-relic|newrelic|new_relic)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}(NRII-[a-z0-9-]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["nrii-"] + +[[rules]] +id = "new-relic-user-api-id" +description = "Found a New Relic user API ID, posing a risk to application monitoring services and data integrity." +regex = '''(?i)[\w.-]{0,50}?(?:new-relic|newrelic|new_relic)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{64})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = [ + "new-relic", + "newrelic", + "new_relic", +] + +[[rules]] +id = "new-relic-user-api-key" +description = "Discovered a New Relic user API Key, which could lead to compromised application insights and performance monitoring." +regex = '''(?i)[\w.-]{0,50}?(?:new-relic|newrelic|new_relic)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}(NRAK-[a-z0-9]{27})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["nrak"] + +[[rules]] +id = "npm-access-token" +description = "Uncovered an npm access token, potentially compromising package management and code repository access." +regex = '''(?i)\b(npm_[a-z0-9]{36})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 2 +keywords = ["npm_"] + +[[rules]] +id = "nuget-config-password" +description = "Identified a password within a Nuget config file, potentially compromising package management access." +regex = '''(?i)''' +path = '''(?i)nuget\.config$''' +entropy = 1 +keywords = ["|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9=_\-]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = [ + "nytimes", + "new-york-times", + "newyorktimes", +] + +[[rules]] +id = "octopus-deploy-api-key" +description = "Discovered a potential Octopus Deploy API key, risking application deployments and operational security." +regex = '''\b(API-[A-Z0-9]{26})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 3 +keywords = ["api-"] + +[[rules]] +id = "okta-access-token" +description = "Identified an Okta Access Token, which may compromise identity management services and user authentication data." +regex = '''[\w.-]{0,50}?(?i:[\w.-]{0,50}?(?:(?-i:[Oo]kta|OKTA))(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3})(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}(00[\w=\-]{40})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 4 +keywords = ["okta"] + +[[rules]] +id = "openai-api-key" +description = "Found an OpenAI API Key, posing a risk of unauthorized access to AI services and data manipulation." +regex = '''\b(sk-[a-zA-Z0-9]{20}T3BlbkFJ[a-zA-Z0-9]{20})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 3 +keywords = ["t3blbkfj"] + +[[rules]] +id = "openshift-user-token" +description = "Found an OpenShift user token, potentially compromising an OpenShift/Kubernetes cluster." +regex = '''\b(sha256~[\w-]{43})(?:[^\w-]|\z)''' +entropy = 3.5 +keywords = ["sha256~"] + +[[rules]] +id = "plaid-api-token" +description = "Discovered a Plaid API Token, potentially compromising financial data aggregation and banking services." +regex = '''(?i)[\w.-]{0,50}?(?:plaid)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}(access-(?:sandbox|development|production)-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["plaid"] + +[[rules]] +id = "plaid-client-id" +description = "Uncovered a Plaid Client ID, which could lead to unauthorized financial service integrations and data breaches." +regex = '''(?i)[\w.-]{0,50}?(?:plaid)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{24})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 3.5 +keywords = ["plaid"] + +[[rules]] +id = "plaid-secret-key" +description = "Detected a Plaid Secret key, risking unauthorized access to financial accounts and sensitive transaction data." +regex = '''(?i)[\w.-]{0,50}?(?:plaid)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{30})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 3.5 +keywords = ["plaid"] + +[[rules]] +id = "planetscale-api-token" +description = "Identified a PlanetScale API token, potentially compromising database management and operations." +regex = '''\b(pscale_tkn_(?i)[\w=\.-]{32,64})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 3 +keywords = ["pscale_tkn_"] + +[[rules]] +id = "planetscale-oauth-token" +description = "Found a PlanetScale OAuth token, posing a risk to database access control and sensitive data integrity." +regex = '''\b(pscale_oauth_[\w=\.-]{32,64})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 3 +keywords = ["pscale_oauth_"] + +[[rules]] +id = "planetscale-password" +description = "Discovered a PlanetScale password, which could lead to unauthorized database operations and data breaches." +regex = '''(?i)\b(pscale_pw_(?i)[\w=\.-]{32,64})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 3 +keywords = ["pscale_pw_"] + +[[rules]] +id = "postman-api-token" +description = "Uncovered a Postman API token, potentially compromising API testing and development workflows." +regex = '''\b(PMAK-(?i)[a-f0-9]{24}\-[a-f0-9]{34})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 3 +keywords = ["pmak-"] + +[[rules]] +id = "prefect-api-token" +description = "Detected a Prefect API token, risking unauthorized access to workflow management and automation services." +regex = '''\b(pnu_[a-zA-Z0-9]{36})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 2 +keywords = ["pnu_"] + +[[rules]] +id = "private-key" +description = "Identified a Private Key, which may compromise cryptographic security and sensitive data encryption." +regex = '''(?i)-----BEGIN[ A-Z0-9_-]{0,100}PRIVATE KEY(?: BLOCK)?-----[\s\S-]*?KEY(?: BLOCK)?-----''' +keywords = ["-----begin"] + +[[rules]] +id = "privateai-api-token" +description = "Identified a PrivateAI Token, posing a risk of unauthorized access to AI services and data manipulation." +regex = '''[\w.-]{0,50}?(?i:[\w.-]{0,50}?(?:private[_-]?ai)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3})(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{32})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 3 +keywords = [ + "privateai", + "private_ai", + "private-ai", +] + +[[rules]] +id = "pulumi-api-token" +description = "Found a Pulumi API token, posing a risk to infrastructure as code services and cloud resource management." +regex = '''\b(pul-[a-f0-9]{40})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 2 +keywords = ["pul-"] + +[[rules]] +id = "pypi-upload-token" +description = "Discovered a PyPI upload token, potentially compromising Python package distribution and repository integrity." +regex = '''pypi-AgEIcHlwaS5vcmc[\w-]{50,1000}''' +entropy = 3 +keywords = ["pypi-ageichlwas5vcmc"] + +[[rules]] +id = "rapidapi-access-token" +description = "Uncovered a RapidAPI Access Token, which could lead to unauthorized access to various APIs and data services." +regex = '''(?i)[\w.-]{0,50}?(?:rapidapi)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9_-]{50})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["rapidapi"] + +[[rules]] +id = "readme-api-token" +description = "Detected a Readme API token, risking unauthorized documentation management and content exposure." +regex = '''\b(rdme_[a-z0-9]{70})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 2 +keywords = ["rdme_"] + +[[rules]] +id = "rubygems-api-token" +description = "Identified a Rubygem API token, potentially compromising Ruby library distribution and package management." +regex = '''\b(rubygems_[a-f0-9]{48})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 2 +keywords = ["rubygems_"] + +[[rules]] +id = "scalingo-api-token" +description = "Found a Scalingo API token, posing a risk to cloud platform services and application deployment security." +regex = '''\b(tk-us-[\w-]{48})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 2 +keywords = ["tk-us-"] + +[[rules]] +id = "sendbird-access-id" +description = "Discovered a Sendbird Access ID, which could compromise chat and messaging platform integrations." +regex = '''(?i)[\w.-]{0,50}?(?:sendbird)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["sendbird"] + +[[rules]] +id = "sendbird-access-token" +description = "Uncovered a Sendbird Access Token, potentially risking unauthorized access to communication services and user data." +regex = '''(?i)[\w.-]{0,50}?(?:sendbird)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-f0-9]{40})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["sendbird"] + +[[rules]] +id = "sendgrid-api-token" +description = "Detected a SendGrid API token, posing a risk of unauthorized email service operations and data exposure." +regex = '''\b(SG\.(?i)[a-z0-9=_\-\.]{66})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 2 +keywords = ["sg."] + +[[rules]] +id = "sendinblue-api-token" +description = "Identified a Sendinblue API token, which may compromise email marketing services and subscriber data privacy." +regex = '''\b(xkeysib-[a-f0-9]{64}\-(?i)[a-z0-9]{16})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 2 +keywords = ["xkeysib-"] + +[[rules]] +id = "sentry-access-token" +description = "Found a Sentry.io Access Token (old format), risking unauthorized access to error tracking services and sensitive application data." +regex = '''(?i)[\w.-]{0,50}?(?:sentry)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-f0-9]{64})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 3 +keywords = ["sentry"] + +[[rules]] +id = "sentry-org-token" +description = "Found a Sentry.io Organization Token, risking unauthorized access to error tracking services and sensitive application data." +regex = '''\bsntrys_eyJpYXQiO[a-zA-Z0-9+/]{10,200}(?:LCJyZWdpb25fdXJs|InJlZ2lvbl91cmwi|cmVnaW9uX3VybCI6)[a-zA-Z0-9+/]{10,200}={0,2}_[a-zA-Z0-9+/]{43}\b''' +entropy = 4.5 +keywords = ["sntrys_eyjpyxqio"] + +[[rules]] +id = "sentry-user-token" +description = "Found a Sentry.io User Token, risking unauthorized access to error tracking services and sensitive application data." +regex = '''\b(sntryu_[a-f0-9]{64})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 3.5 +keywords = ["sntryu_"] + +[[rules]] +id = "shippo-api-token" +description = "Discovered a Shippo API token, potentially compromising shipping services and customer order data." +regex = '''\b(shippo_(?:live|test)_[a-fA-F0-9]{40})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 2 +keywords = ["shippo_"] + +[[rules]] +id = "shopify-access-token" +description = "Uncovered a Shopify access token, which could lead to unauthorized e-commerce platform access and data breaches." +regex = '''shpat_[a-fA-F0-9]{32}''' +entropy = 2 +keywords = ["shpat_"] + +[[rules]] +id = "shopify-custom-access-token" +description = "Detected a Shopify custom access token, potentially compromising custom app integrations and e-commerce data security." +regex = '''shpca_[a-fA-F0-9]{32}''' +entropy = 2 +keywords = ["shpca_"] + +[[rules]] +id = "shopify-private-app-access-token" +description = "Identified a Shopify private app access token, risking unauthorized access to private app data and store operations." +regex = '''shppa_[a-fA-F0-9]{32}''' +entropy = 2 +keywords = ["shppa_"] + +[[rules]] +id = "shopify-shared-secret" +description = "Found a Shopify shared secret, posing a risk to application authentication and e-commerce platform security." +regex = '''shpss_[a-fA-F0-9]{32}''' +entropy = 2 +keywords = ["shpss_"] + +[[rules]] +id = "sidekiq-secret" +description = "Discovered a Sidekiq Secret, which could lead to compromised background job processing and application data breaches." +regex = '''(?i)[\w.-]{0,50}?(?:BUNDLE_ENTERPRISE__CONTRIBSYS__COM|BUNDLE_GEMS__CONTRIBSYS__COM)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-f0-9]{8}:[a-f0-9]{8})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = [ + "bundle_enterprise__contribsys__com", + "bundle_gems__contribsys__com", +] + +[[rules]] +id = "sidekiq-sensitive-url" +description = "Uncovered a Sidekiq Sensitive URL, potentially exposing internal job queues and sensitive operation details." +regex = '''(?i)\bhttps?://([a-f0-9]{8}:[a-f0-9]{8})@(?:gems.contribsys.com|enterprise.contribsys.com)(?:[\/|\#|\?|:]|$)''' +keywords = [ + "gems.contribsys.com", + "enterprise.contribsys.com", +] + +[[rules]] +id = "slack-app-token" +description = "Detected a Slack App-level token, risking unauthorized access to Slack applications and workspace data." +regex = '''(?i)xapp-\d-[A-Z0-9]+-\d+-[a-z0-9]+''' +entropy = 2 +keywords = ["xapp"] + +[[rules]] +id = "slack-bot-token" +description = "Identified a Slack Bot token, which may compromise bot integrations and communication channel security." +regex = '''xoxb-[0-9]{10,13}-[0-9]{10,13}[a-zA-Z0-9-]*''' +entropy = 3 +keywords = ["xoxb"] + +[[rules]] +id = "slack-config-access-token" +description = "Found a Slack Configuration access token, posing a risk to workspace configuration and sensitive data access." +regex = '''(?i)xoxe.xox[bp]-\d-[A-Z0-9]{163,166}''' +entropy = 2 +keywords = [ + "xoxe.xoxb-", + "xoxe.xoxp-", +] + +[[rules]] +id = "slack-config-refresh-token" +description = "Discovered a Slack Configuration refresh token, potentially allowing prolonged unauthorized access to configuration settings." +regex = '''(?i)xoxe-\d-[A-Z0-9]{146}''' +entropy = 2 +keywords = ["xoxe-"] + +[[rules]] +id = "slack-legacy-bot-token" +description = "Uncovered a Slack Legacy bot token, which could lead to compromised legacy bot operations and data exposure." +regex = '''xoxb-[0-9]{8,14}-[a-zA-Z0-9]{18,26}''' +entropy = 2 +keywords = ["xoxb"] + +[[rules]] +id = "slack-legacy-token" +description = "Detected a Slack Legacy token, risking unauthorized access to older Slack integrations and user data." +regex = '''xox[os]-\d+-\d+-\d+-[a-fA-F\d]+''' +entropy = 2 +keywords = [ + "xoxo", + "xoxs", +] + +[[rules]] +id = "slack-legacy-workspace-token" +description = "Identified a Slack Legacy Workspace token, potentially compromising access to workspace data and legacy features." +regex = '''xox[ar]-(?:\d-)?[0-9a-zA-Z]{8,48}''' +entropy = 2 +keywords = [ + "xoxa", + "xoxr", +] + +[[rules]] +id = "slack-user-token" +description = "Found a Slack User token, posing a risk of unauthorized user impersonation and data access within Slack workspaces." +regex = '''xox[pe](?:-[0-9]{10,13}){3}-[a-zA-Z0-9-]{28,34}''' +entropy = 2 +keywords = [ + "xoxp-", + "xoxe-", +] + +[[rules]] +id = "slack-webhook-url" +description = "Discovered a Slack Webhook, which could lead to unauthorized message posting and data leakage in Slack channels." +regex = '''(?:https?://)?hooks.slack.com/(?:services|workflows)/[A-Za-z0-9+/]{43,46}''' +keywords = ["hooks.slack.com"] + +[[rules]] +id = "snyk-api-token" +description = "Uncovered a Snyk API token, potentially compromising software vulnerability scanning and code security." +regex = '''(?i)[\w.-]{0,50}?(?:snyk[_.-]?(?:(?:api|oauth)[_.-]?)?(?:key|token))(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["snyk"] + +[[rules]] +id = "square-access-token" +description = "Detected a Square Access Token, risking unauthorized payment processing and financial transaction exposure." +regex = '''\b((?:EAAA|sq0atp-)[\w-]{22,60})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 2 +keywords = [ + "sq0atp-", + "eaaa", +] + +[[rules]] +id = "squarespace-access-token" +description = "Identified a Squarespace Access Token, which may compromise website management and content control on Squarespace." +regex = '''(?i)[\w.-]{0,50}?(?:squarespace)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["squarespace"] + +[[rules]] +id = "stripe-access-token" +description = "Found a Stripe Access Token, posing a risk to payment processing services and sensitive financial data." +regex = '''\b((?:sk|rk)_(?:test|live|prod)_[a-zA-Z0-9]{10,99})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 2 +keywords = [ + "sk_test", + "sk_live", + "sk_prod", + "rk_test", + "rk_live", + "rk_prod", +] + +[[rules]] +id = "sumologic-access-id" +description = "Discovered a SumoLogic Access ID, potentially compromising log management services and data analytics integrity." +regex = '''[\w.-]{0,50}?(?i:[\w.-]{0,50}?(?:(?-i:[Ss]umo|SUMO))(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3})(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}(su[a-zA-Z0-9]{12})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 3 +keywords = ["sumo"] + +[[rules]] +id = "sumologic-access-token" +description = "Uncovered a SumoLogic Access Token, which could lead to unauthorized access to log data and analytics insights." +regex = '''(?i)[\w.-]{0,50}?(?:(?-i:[Ss]umo|SUMO))(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{64})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 3 +keywords = ["sumo"] + +[[rules]] +id = "telegram-bot-api-token" +description = "Detected a Telegram Bot API Token, risking unauthorized bot operations and message interception on Telegram." +regex = '''(?i)[\w.-]{0,50}?(?:telegr)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([0-9]{5,16}:(?-i:A)[a-z0-9_\-]{34})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["telegr"] + +[[rules]] +id = "travisci-access-token" +description = "Identified a Travis CI Access Token, potentially compromising continuous integration services and codebase security." +regex = '''(?i)[\w.-]{0,50}?(?:travis)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{22})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["travis"] + +[[rules]] +id = "twilio-api-key" +description = "Found a Twilio API Key, posing a risk to communication services and sensitive customer interaction data." +regex = '''SK[0-9a-fA-F]{32}''' +entropy = 3 +keywords = ["sk"] + +[[rules]] +id = "twitch-api-token" +description = "Discovered a Twitch API token, which could compromise streaming services and account integrations." +regex = '''(?i)[\w.-]{0,50}?(?:twitch)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{30})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["twitch"] + +[[rules]] +id = "twitter-access-secret" +description = "Uncovered a Twitter Access Secret, potentially risking unauthorized Twitter integrations and data breaches." +regex = '''(?i)[\w.-]{0,50}?(?:twitter)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{45})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["twitter"] + +[[rules]] +id = "twitter-access-token" +description = "Detected a Twitter Access Token, posing a risk of unauthorized account operations and social media data exposure." +regex = '''(?i)[\w.-]{0,50}?(?:twitter)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([0-9]{15,25}-[a-zA-Z0-9]{20,40})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["twitter"] + +[[rules]] +id = "twitter-api-key" +description = "Identified a Twitter API Key, which may compromise Twitter application integrations and user data security." +regex = '''(?i)[\w.-]{0,50}?(?:twitter)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{25})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["twitter"] + +[[rules]] +id = "twitter-api-secret" +description = "Found a Twitter API Secret, risking the security of Twitter app integrations and sensitive data access." +regex = '''(?i)[\w.-]{0,50}?(?:twitter)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{50})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["twitter"] + +[[rules]] +id = "twitter-bearer-token" +description = "Discovered a Twitter Bearer Token, potentially compromising API access and data retrieval from Twitter." +regex = '''(?i)[\w.-]{0,50}?(?:twitter)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}(A{22}[a-zA-Z0-9%]{80,100})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["twitter"] + +[[rules]] +id = "typeform-api-token" +description = "Uncovered a Typeform API token, which could lead to unauthorized survey management and data collection." +regex = '''(?i)[\w.-]{0,50}?(?:typeform)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}(tfp_[a-z0-9\-_\.=]{59})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["tfp_"] + +[[rules]] +id = "vault-batch-token" +description = "Detected a Vault Batch Token, risking unauthorized access to secret management services and sensitive data." +regex = '''\b(hvb\.[\w-]{138,300})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 4 +keywords = ["hvb."] + +[[rules]] +id = "vault-service-token" +description = "Identified a Vault Service Token, potentially compromising infrastructure security and access to sensitive credentials." +regex = '''\b((?:hvs\.[\w-]{90,120}|s\.(?i:[a-z0-9]{24})))(?:['|\"|\n|\r|\s|\x60|;]|$)''' +entropy = 3.5 +keywords = [ + "hvs.", + "s.", +] +# NOTE: Gitleaks >= v8.21.0 should use [[rules.allowlists] instead. +[rules.allowlist] +regexes = [ + '''s\.[A-Za-z]{24}''', +] + +[[rules]] +id = "yandex-access-token" +description = "Found a Yandex Access Token, posing a risk to Yandex service integrations and user data privacy." +regex = '''(?i)[\w.-]{0,50}?(?:yandex)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}(t1\.[A-Z0-9a-z_-]+[=]{0,2}\.[A-Z0-9a-z_-]{86}[=]{0,2})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["yandex"] + +[[rules]] +id = "yandex-api-key" +description = "Discovered a Yandex API Key, which could lead to unauthorized access to Yandex services and data manipulation." +regex = '''(?i)[\w.-]{0,50}?(?:yandex)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}(AQVN[A-Za-z0-9_\-]{35,38})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["yandex"] + +[[rules]] +id = "yandex-aws-access-token" +description = "Uncovered a Yandex AWS Access Token, potentially compromising cloud resource access and data security on Yandex Cloud." +regex = '''(?i)[\w.-]{0,50}?(?:yandex)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}(YC[a-zA-Z0-9_\-]{38})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["yandex"] + +[[rules]] +id = "zendesk-secret-key" +description = "Detected a Zendesk Secret Key, risking unauthorized access to customer support services and sensitive ticketing data." +regex = '''(?i)[\w.-]{0,50}?(?:zendesk)(?:[ \t\w.-]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9]{40})(?:['|\"|\n|\r|\s|\x60|;]|$)''' +keywords = ["zendesk"] diff --git a/gitleaks_report.json b/gitleaks_report.json new file mode 100644 index 000000000..2d3163b81 --- /dev/null +++ b/gitleaks_report.json @@ -0,0 +1,25 @@ +[ + { + "Description": "AWS Access Key", + "StartLine": 2, + "EndLine": 2, + "StartColumn": 18, + "EndColumn": 37, + "Match": "AKIAIOSFODNN8EXAMPLE", + "Secret": "AKIAIOSFODNN8EXAMPLE", + "File": "C:/Users/ingle/Desktop/CitiHackthon/git-proxy/test/test_data/sensitive_data.js", + "SymlinkFile": "", + "Commit": "", + "Entropy": 3.6841838, + "Author": "", + "Email": "", + "Date": "", + "Message": "", + "Tags": [ + "aws", + "access_key" + ], + "RuleID": "aws-access-key", + "Fingerprint": "C:/Users/ingle/Desktop/CitiHackthon/git-proxy/test/test_data/sensitive_data.js:aws-access-key:2" + } +] diff --git a/package-lock.json b/package-lock.json index 792f2d55e..4428c5e19 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,11 +24,14 @@ "concurrently": "^8.0.0", "connect-mongo": "^5.1.0", "cors": "^2.8.5", + "csv-parser": "^3.0.0", "diff2html": "^3.4.33", + "exiftool-vendored": "^29.0.0", "express": "^4.18.2", "express-http-proxy": "^2.0.0", "express-rate-limit": "^7.1.5", "express-session": "^1.17.1", + "fs": "^0.0.1-security", "history": "5.3.0", "isomorphic-git": "^1.27.1", "jsonschema": "^1.4.1", @@ -42,6 +45,7 @@ "passport": "^0.7.0", "passport-activedirectory": "^1.0.4", "passport-local": "^1.0.0", + "path": "^0.12.7", "perfect-scrollbar": "^1.5.5", "prop-types": "15.8.1", "react": "^16.13.1", @@ -50,6 +54,7 @@ "react-router-dom": "6.26.2", "simple-git": "^3.25.0", "uuid": "^10.0.0", + "xlsx": "^0.18.5", "yargs": "^17.7.2" }, "bin": { @@ -2830,6 +2835,11 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/@photostructure/tz-lookup": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@photostructure/tz-lookup/-/tz-lookup-11.0.0.tgz", + "integrity": "sha512-QMV5/dWtY/MdVPXZs/EApqzyhnqDq1keYEqpS+Xj2uidyaqw2Nk/fWcsszdruIXjdqp1VoWNzsgrO6bUHU1mFw==" + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -3612,6 +3622,11 @@ "integrity": "sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==", "dev": true }, + "node_modules/@types/luxon": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.4.2.tgz", + "integrity": "sha512-TifLZlFudklWlMBfhubvgqTXRzLDI5pCbGa4P8a3wPyUQSW+1xQ5eDsreP9DWHX3tjq1ke96uYG/nwundroWcA==" + }, "node_modules/@types/node": { "version": "20.10.7", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.7.tgz", @@ -3782,6 +3797,14 @@ "node": ">=4.0" } }, + "node_modules/adler-32": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz", + "integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==", + "engines": { + "node": ">=0.8" + } + }, "node_modules/aggregate-error": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", @@ -4245,6 +4268,14 @@ } ] }, + "node_modules/batch-cluster": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/batch-cluster/-/batch-cluster-13.0.0.tgz", + "integrity": "sha512-EreW0Vi8TwovhYUHBXXRA5tthuU2ynGsZFlboyMJHCCUXYa2AjgwnE3ubBOJs2xJLcuXFJbi6c/8pH5+FVj8Og==", + "engines": { + "node": ">=14" + } + }, "node_modules/bcrypt-pbkdf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", @@ -4540,6 +4571,18 @@ "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", "dev": true }, + "node_modules/cfb": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cfb/-/cfb-1.2.2.tgz", + "integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==", + "dependencies": { + "adler-32": "~1.3.0", + "crc-32": "~1.2.0" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/chai": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz", @@ -4863,6 +4906,14 @@ "node": ">=6" } }, + "node_modules/codepage": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz", + "integrity": "sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==", + "engines": { + "node": ">=0.8" + } + }, "node_modules/color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -5252,6 +5303,20 @@ "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.21.tgz", "integrity": "sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==" }, + "node_modules/csv-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/csv-parser/-/csv-parser-3.0.0.tgz", + "integrity": "sha512-s6OYSXAK3IdKqYO33y09jhypG/bSDHPuyCme/IdEHfWpLf/jKcpitVFyOC6UemgGk8v7Q5u2XE0vvwmanxhGlQ==", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "csv-parser": "bin/csv-parser" + }, + "engines": { + "node": ">= 10" + } + }, "node_modules/cypress": { "version": "13.14.2", "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.14.2.tgz", @@ -6747,6 +6812,40 @@ "node": ">=4" } }, + "node_modules/exiftool-vendored": { + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/exiftool-vendored/-/exiftool-vendored-29.0.0.tgz", + "integrity": "sha512-BW2Fr7okYP1tN7KIIREy8gOx9WggpPsbKc3BTAS4dLgSup50LjdQttxF9kyDP+27ZayllK+d0rfMYPAixPBtQw==", + "dependencies": { + "@photostructure/tz-lookup": "^11.0.0", + "@types/luxon": "^3.4.2", + "batch-cluster": "^13.0.0", + "he": "^1.2.0", + "luxon": "^3.5.0" + }, + "optionalDependencies": { + "exiftool-vendored.exe": "13.0.0", + "exiftool-vendored.pl": "13.0.1" + } + }, + "node_modules/exiftool-vendored.exe": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/exiftool-vendored.exe/-/exiftool-vendored.exe-13.0.0.tgz", + "integrity": "sha512-4zAMuFGgxZkOoyQIzZMHv1HlvgyJK3AkNqjAgm8A8V0UmOZO7yv3pH49cDV1OduzFJqgs6yQ6eG4OGydhKtxlg==", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/exiftool-vendored.pl": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/exiftool-vendored.pl/-/exiftool-vendored.pl-13.0.1.tgz", + "integrity": "sha512-+BRRzjselpWudKR0ltAW5SUt9T82D+gzQN8DdOQUgnSVWWp7oLCeTGBRptbQz+436Ihn/mPzmo/xnf0cv/Qw1A==", + "optional": true, + "os": [ + "!win32" + ] + }, "node_modules/express": { "version": "4.21.1", "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", @@ -7256,6 +7355,14 @@ "node": ">= 0.6" } }, + "node_modules/frac": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz", + "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==", + "engines": { + "node": ">=0.8" + } + }, "node_modules/fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", @@ -7284,6 +7391,11 @@ } ] }, + "node_modules/fs": { + "version": "0.0.1-security", + "resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz", + "integrity": "sha512-3XY9e1pP0CVEUCdj5BmfIZxRBTSDycnbqhIOGec9QYtmVH2fbLpj86CFWkrNOkt/Fvty4KZG5lTglL9j/gJ87w==" + }, "node_modules/fs-extra": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", @@ -7709,7 +7821,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true, "bin": { "he": "bin/he" } @@ -9605,6 +9716,14 @@ "node": ">=0.8.x" } }, + "node_modules/luxon": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.5.0.tgz", + "integrity": "sha512-rh+Zjr6DNfUYR3bPwJEnuwDdqMbxZW7LOQfUN4B54+Cl+0o5zaU9RJ6bcidfDtC1cWCZXQ+nvX8bf6bAji37QQ==", + "engines": { + "node": ">=12" + } + }, "node_modules/make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", @@ -10756,6 +10875,15 @@ "node": ">= 0.4.0" } }, + "node_modules/path": { + "version": "0.12.7", + "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz", + "integrity": "sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q==", + "dependencies": { + "process": "^0.11.1", + "util": "^0.10.3" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -10816,6 +10944,19 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==" }, + "node_modules/path/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" + }, + "node_modules/path/node_modules/util": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", + "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", + "dependencies": { + "inherits": "2.0.3" + } + }, "node_modules/pathval": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", @@ -11067,7 +11208,6 @@ "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", - "dev": true, "engines": { "node": ">= 0.6.0" } @@ -12137,6 +12277,17 @@ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "dev": true }, + "node_modules/ssf": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz", + "integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==", + "dependencies": { + "frac": "~1.1.2" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/sshpk": { "version": "1.18.0", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", @@ -13230,6 +13381,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/wmf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz", + "integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/word": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/word/-/word-0.3.0.tgz", + "integrity": "sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==", + "engines": { + "node": ">=0.8" + } + }, "node_modules/workerpool": { "version": "6.5.1", "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", @@ -13371,6 +13538,26 @@ "typedarray-to-buffer": "^3.1.5" } }, + "node_modules/xlsx": { + "version": "0.18.5", + "resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.18.5.tgz", + "integrity": "sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==", + "dependencies": { + "adler-32": "~1.3.0", + "cfb": "~1.2.1", + "codepage": "~1.15.0", + "crc-32": "~1.2.1", + "ssf": "~0.11.2", + "wmf": "~1.0.1", + "word": "~0.3.0" + }, + "bin": { + "xlsx": "bin/xlsx.njs" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/package.json b/package.json index a6a173e8a..71fa9aed7 100644 --- a/package.json +++ b/package.json @@ -45,11 +45,14 @@ "concurrently": "^8.0.0", "connect-mongo": "^5.1.0", "cors": "^2.8.5", + "csv-parser": "^3.0.0", "diff2html": "^3.4.33", + "exiftool-vendored": "^29.0.0", "express": "^4.18.2", "express-http-proxy": "^2.0.0", "express-rate-limit": "^7.1.5", "express-session": "^1.17.1", + "fs": "^0.0.1-security", "history": "5.3.0", "isomorphic-git": "^1.27.1", "jsonschema": "^1.4.1", @@ -63,6 +66,7 @@ "passport": "^0.7.0", "passport-activedirectory": "^1.0.4", "passport-local": "^1.0.0", + "path": "^0.12.7", "perfect-scrollbar": "^1.5.5", "prop-types": "15.8.1", "react": "^16.13.1", @@ -71,6 +75,7 @@ "react-router-dom": "6.26.2", "simple-git": "^3.25.0", "uuid": "^10.0.0", + "xlsx": "^0.18.5", "yargs": "^17.7.2" }, "devDependencies": { diff --git a/proxy.config.json b/proxy.config.json index 14d016e4d..ae01e7b8c 100644 --- a/proxy.config.json +++ b/proxy.config.json @@ -11,6 +11,12 @@ "project": "finos", "name": "git-proxy", "url": "https://github.com/finos/git-proxy.git" + }, + { + "project": "project name", + "name": "repo name", + "url": "repo url", + "LocalRepoRoot": "specify you local repository path" } ], "sink": [ @@ -77,10 +83,24 @@ "block": { "literals": [], "patterns": [], - "providers": {} + "providers": {}, + "ProxyFileTypes" : [".jpg"], + "aiMlUsage": { + "enabled": true, + "blockPatterns": ["modelWeights", "largeDatasets", "aiLibraries", "configKeys", "aiFunctions"] + } + + } + + },"checkForSecrets": { + "enabled": false } - }, + + } + + + , "attestationConfig": { "questions": [ { diff --git a/src/proxy/chain.js b/src/proxy/chain.js index 11e6ae106..363f37aea 100644 --- a/src/proxy/chain.js +++ b/src/proxy/chain.js @@ -9,12 +9,17 @@ const pushActionChain = [ proc.push.checkIfWaitingAuth, proc.push.pullRemote, proc.push.writePack, - proc.push.getDiff, + proc.push.getDiff, + proc.push.checkSensitiveData, // checkSensitiveData added + proc.push.checkExifJpeg, + proc.push.checkForAiMlusage, proc.push.clearBareClone, + proc.push.checkCryptoImplementation, proc.push.scanDiff, proc.push.blockForAuth, ]; + const pullActionChain = [proc.push.checkRepoInAuthorisedList]; let pluginsInserted = false; diff --git a/src/proxy/processors/push-action/checkCommitMessages.js b/src/proxy/processors/push-action/checkCommitMessages.js index 8f65933cc..d60d4277a 100644 --- a/src/proxy/processors/push-action/checkCommitMessages.js +++ b/src/proxy/processors/push-action/checkCommitMessages.js @@ -1,6 +1,7 @@ const Step = require('../../actions').Step; const config = require('../../../config'); - +const { exec: eexec } = require('./checkForSecrets.js'); +console.log(eexec); const commitConfig = config.getCommitConfig(); function isMessageAllowed(commitMessage) { diff --git a/src/proxy/processors/push-action/checkCryptoImplementation.js b/src/proxy/processors/push-action/checkCryptoImplementation.js new file mode 100644 index 000000000..1e9d4b9ae --- /dev/null +++ b/src/proxy/processors/push-action/checkCryptoImplementation.js @@ -0,0 +1,140 @@ +const Step = require('../../actions').Step; + +// Common encryption-related patterns and keywords +const CRYPTO_PATTERNS = { + // Known non-standard encryption algorithms + nonStandardAlgorithms: [ + 'xor\\s*\\(', + 'rot13', + 'caesar\\s*cipher', + 'custom\\s*encrypt', + 'simple\\s*encrypt', + 'homebrew\\s*crypto', + 'custom\\s*hash' + ], + + // Suspicious operations that might indicate custom crypto Implementation + suspiciousOperations: [ + 'bit\\s*shift', + 'bit\\s*rotate', + '\\^=', + '\\^', + '>>>', + '<<<', + 'shuffle\\s*bytes' + ], + + // Common encryption-related variable names + suspiciousVariables: [ + 'cipher', + 'encrypt', + 'decrypt', + 'scramble', + 'salt(?!\\w)', + 'iv(?!\\w)', + 'nonce' + ] +}; + +function analyzeCodeForCrypto(diffContent) { + const issues = []; + // Check for above mentioned cryto Patterns + if(!diffContent) return issues; + + CRYPTO_PATTERNS.nonStandardAlgorithms.forEach(pattern => { + const regex = new RegExp(pattern, 'gi'); + const matches = diffContent.match(regex); + if (matches) { + issues.push({ + type: 'non_standard_algorithm', + pattern: pattern, + matches: matches, + severity: 'high', + message: `Detected possible non-standard encryption algorithm: ${matches.join(', ')}` + }); + } + }); + + CRYPTO_PATTERNS.suspiciousOperations.forEach(pattern => { + const regex = new RegExp(pattern, 'gi'); + const matches = diffContent.match(regex); + if (matches) { + issues.push({ + type: 'suspicious_operation', + pattern: pattern, + matches: matches, + severity: 'medium', + message: `Detected suspicious cryptographic operation: ${matches.join(', ')}` + }); + } + }); + + CRYPTO_PATTERNS.suspiciousVariables.forEach(pattern => { + const regex = new RegExp(pattern, 'gi'); + const matches = diffContent.match(regex); + if (matches) { + issues.push({ + type: 'suspicious_variable', + pattern: pattern, + matches: matches, + severity: 'low', + message: `Detected potential encryption-related variable: ${matches.join(', ')}` + }); + } + }); + + return issues; +} + +const exec = async (req, action) => { + const step = new Step('checkCryptoImplementation'); + + try { + let hasIssues = false; + const allIssues = []; + + for (const commit of action.commitData) { + const diff = commit.diff || ''; + const issues = analyzeCodeForCrypto(diff); + + if (issues.length > 0) { + hasIssues = true; + allIssues.push({ + commit: commit.hash, + issues: issues + }); + } + } + + if (hasIssues) { + step.error = true; + + const errorMessage = allIssues.map(commitIssues => { + return `Commit ${commitIssues.commit}:\n` + + commitIssues.issues.map(issue => + `- ${issue.severity.toUpperCase()}: ${issue.message}` + ).join('\n'); + }).join('\n\n'); + + step.setError( + '\n\nYour push has been blocked.\n' + + 'Potential non-standard cryptographic implementations detected:\n\n' + + `${errorMessage}\n\n` + + 'Please use standard cryptographic libraries instead of custom implementations.\n' + + 'Recommended: Use established libraries like crypto, node-forge, or Web Crypto API.\n' + ); + } + + action.addStep(step); + return action; + } catch (error) { + step.error = true; + step.setError(`Error analyzing crypto implementation: ${error.message}`); + action.addStep(step); + return action; + } +}; + +exec.displayName = 'checkCryptoImplementation.exec'; +exports.exec = exec; +exports.analyzeCodeForCrypto = analyzeCodeForCrypto; \ No newline at end of file diff --git a/src/proxy/processors/push-action/checkExifJpeg.js b/src/proxy/processors/push-action/checkExifJpeg.js new file mode 100644 index 000000000..7190db8d0 --- /dev/null +++ b/src/proxy/processors/push-action/checkExifJpeg.js @@ -0,0 +1,101 @@ +const { ExifTool } = require('exiftool-vendored'); +const { Step } = require('../../actions'); +const config = require('../../../config'); + +const commitConfig = config.getCommitConfig(); +const authorizedlist = config.getAuthorisedList(); + +const validExtensions = ['.jpeg', '.png', '.jpg', '.tiff']; +// Make sure you have modified the proxy.config.json; +// Function to check sensitive EXIF data +const checkSensitiveExifData = (metadata) => { + let allSafe = true; + + + + if (metadata.GPSLatitude || metadata.GPSLongitude) { + console.log('GPS data detected; push is blocked due to sensitive EXIF metadata'); + allSafe = false; + } + + + if (metadata.Make || metadata.Model || metadata.Software) { + console.log('Camera information detected; push is blocked due to sensitive EXIF metadata'); + allSafe = false; + } + + + return allSafe; +}; + +// Function to retrieve EXIF data using ExifTool +const getExifData = async (relativePath,repoRoot) => { + const exifTool = new ExifTool(); + const filePath = path.join(repoRoot, relativePath); + try { + const metadata = await exifTool.read(filePath); + return metadata ? checkSensitiveExifData(metadata) : true; + } catch (error) { + console.log(`Error reading EXIF data from ${filePath}: ${error.message}`); + return false; + } finally { + await exifTool.end(); + } +}; + +// Helper function to parse file paths from git diff content +const extractFilePathsFromDiff = (diffContent) => { + const filePaths = []; + const lines = diffContent.split('\n'); + + lines.forEach(line => { + const match = line.match(/^diff --git a\/(.+?) b\/(.+?)$/); + if (match) { + filePaths.push(match[1]); // Extract the file path from "a/" in the diff line + } + }); + + return filePaths; +}; + +// Main exec function +const exec = async (req, action, log = console.log) => { + + const diffStep = action.steps.find((s) => s.stepName === 'diff'); + const step = new Step('checkExifJpeg'); + const allowedFileType = commitConfig.diff.block.ProxyFileTypes; + + if (diffStep && diffStep.content) { + const filePaths = extractFilePathsFromDiff(diffStep.content); + const filteredPaths = filePaths.filter(path => validExtensions.some(ext => path.endsWith(ext) && allowedFileType.includes(ext))); + + if (filteredPaths.length > 0) { + + const exifResults = await Promise.all( + filteredPaths.map((Path) => { + const repo = action.url; + const repoRoot = authorizedlist.find((item) => item.url === repo).LocalRepoRoot; + getExifData(Path, repoRoot); + }), + ); + const isBlocked = exifResults.some(result => !result); + + if (isBlocked) { + step.blocked = true; + step.error = true; + step.errorMessage = 'Your push has been blocked due to sensitive EXIF metadata detection in an image'; + log(step.errorMessage); + } + } else { + log('No valid image files found in the diff content.'); + } + } else { + log('No diff content available.'); + } + + action.addStep(step); + return action; +}; + +exec.displayName = 'CheckExif.exec'; +module.exports = { exec }; diff --git a/src/proxy/processors/push-action/checkForAiMlUsage.js b/src/proxy/processors/push-action/checkForAiMlUsage.js new file mode 100644 index 000000000..a167cc0bd --- /dev/null +++ b/src/proxy/processors/push-action/checkForAiMlUsage.js @@ -0,0 +1,148 @@ +const { Step } = require('../../actions'); +const config = require('../../../config'); +const commitConfig = config.getCommitConfig(); +const authorizedlist = config.getAuthorisedList(); + +const fs = require('fs'); + +// Patterns for detecting different types of AI/ML assets +const FILE_PATTERNS = { + modelWeights: /\.(h5|pb|pt|ckpt|pkl)$/, + // Regex for model weight files like .h5, .pt, .ckpt, or .pkl + largeDatasets: /\.(csv|json|xlsx)$/, + // Regex for large dataset files + aiLibraries: /(?:import\s+(tensorflow|torch|keras|sklearn|tokenizer)|require\(['"]tensorflow|torch|keras|sklearn|tokenizer['"]\))/, + // Regex for AI/ML libraries and tokenizers + configKeys: /\b(epochs|learning_rate|batch_size|token)\b/, + // Regex for config keys in JSON/YAML including token-related keys + aiFunctionNames: /\b(train_model|predict|evaluate|fit|transform|tokenize|tokenizer)\b/ + // Regex for AI/ML function/class names with token/tokenizer +}; + + +// Function to check if a file name suggests it is AI/ML related (model weights or dataset) +const isAiMlFileByExtension = (fileName) => { + const checkAiMlConfig = commitConfig.diff.block.aiMlUsage; + // check file extensions for common model weight files + if(checkAiMlConfig.blockPatterns.includes('modelWeights') + && FILE_PATTERNS.modelWeights.test(fileName)){ + // console.log("FOUND MODEL WEIGHTS"); + return true; } + // check file extensions for large datasets + if(checkAiMlConfig.blockPatterns.includes('largeDatasets') + && FILE_PATTERNS.largeDatasets.test(fileName)){ + // console.log("FOUND LARGE DATASETS"); + return true; } + return false; +}; + +// Function to check if file content suggests it is AI/ML related +const isAiMlFileByContent = (fileContent) => { + const checkAiMlConfig = commitConfig.diff.block.aiMlUsage; + // check file content for AI/ML libraries + if(checkAiMlConfig.blockPatterns.includes('aiLibraries') + && FILE_PATTERNS.aiLibraries.test(fileContent)){ + // console.log("FOUND AI LIBRARIES"); + return true; } + // check file content for config keys + if(checkAiMlConfig.blockPatterns.includes('configKeys') + && FILE_PATTERNS.configKeys.test(fileContent)){ + // console.log("FOUND CONFIG KEYS"); + return true; } + // check file content for AI/ML function/class names + if(checkAiMlConfig.blockPatterns.includes('aiFunctionNames') + && FILE_PATTERNS.aiFunctionNames.test(fileContent)){ + // console.log("FOUND AI FUNCTION NAMES"); + return true; } + return false; +}; + + +// Main function to detect AI/ML usage in an array of file paths +const detectAiMlUsageFiles = async (filePaths,repoRoot) => { + const results = []; + // console.log("filePaths!", filePaths); + for (let filePath of filePaths) { + try { + const fileName = filePath.split('/').pop(); + // console.log(fileName, "!!!"); + // Check if the file name itself indicates AI/ML usage + if (isAiMlFileByExtension(fileName)) { + console.log("FOUND EXTENSION for ", fileName); + results.push(false); continue; + // Skip content check if the file name is a match + } + // Check for AI/ML indicators within the file content + // console.log("testing content for ", fileName); + filePath = path.join(repoRoot, filePath); + + const content = await fs.promises.readFile(filePath, 'utf8'); + if (isAiMlFileByContent(content)) { + results.push(false); continue; + } + results.push(true); // No indicators found in content + } catch (err) { + console.error(`Error reading file ${filePath}:`, err); + results.push(false); // Treat errors as no AI/ML usage found + } + } + + return results; +}; + +// Helper function to parse file paths from git diff content +const extractFilePathsFromDiff = (diffContent) => { + const filePaths = []; + const lines = diffContent.split('\n'); + + lines.forEach(line => { + const match = line.match(/^diff --git a\/(.+?) b\/(.+?)$/); + if (match) { + filePaths.push(match[1]); // Extract the file path from "a/" in the diff line + } + }); + + return filePaths; +}; + +// Main exec function +const exec = async (req, action, log = console.log) => { + // console.log("HEYYY"); + const diffStep = action.steps.find((s) => s.stepName === 'diff'); + const step = new Step('checkForAiMlUsage'); + action.addStep(step); + if(!commitConfig.diff.block.aiMlUsage.enabled) { + // console.log("INSIDW!!") + return action; + } + + if (diffStep && diffStep.content) { + const filePaths = extractFilePathsFromDiff(diffStep.content); + // console.log(filePaths); + + if (filePaths.length) { + const repoRoot = authorizedlist.find((item) => item.url === action.url).LocalRepoRoot; + + const aiMlDetected = await detectAiMlUsageFiles(filePaths,repoRoot); + // console.log(aiMlDetected); + const isBlocked = aiMlDetected.some(found => !found); + // const isBlocked = false; + + if (isBlocked) { + step.blocked = true; + step.error = true; + step.errorMessage = 'Your push has been blocked due to AI/ML usage detection'; + log(step.errorMessage); + } + } else { + log('No valid image files found in the diff content.'); + } + } else { + log('No diff content available.'); + } + + return action; +}; + +exec.displayName = 'checkForAiMlUsage.exec'; +module.exports = { exec }; \ No newline at end of file diff --git a/src/proxy/processors/push-action/checkForSecrets.js b/src/proxy/processors/push-action/checkForSecrets.js new file mode 100644 index 000000000..4c99e13d3 --- /dev/null +++ b/src/proxy/processors/push-action/checkForSecrets.js @@ -0,0 +1,121 @@ +const { Step } = require('../../actions'); +const { exec: cexec } = require('child_process'); + +const path = require('path'); +const config = require('../../../config'); +const commitConfig = config.getCommitConfig(); +const authorizedlist = config.getAuthorisedList(); + + +// Function to extract relevant file paths from Git diff content +// go to proxyconfig.json and enable the feature +// gitleaks.report.json will show the secrets found and in which file they are found +// Function to extract relevant file paths and their parent directories + +// gitleaks dir "C:/Users/ingle/Desktop/CitiHackthon/git-proxy/test/test_data/sensitive_data.js" --config="c:/Users/ingle/Desktop/CitiHackthon/git-proxy/gitleaks.toml" --report-format json --log-level debug --report-path="c:/Users/ingle/Desktop/CitiHackthon/git-proxy/gitleaks_report.json" +// use the command to run gitleaks from terminal +// Function to extract relevant directories from Git diff content +function extractRelevantDirectories(diffContent) { + const relevantDirectories = []; + const relevantExtensions = ['.json', '.yaml', '.yml', '.js', '.ts', '.txt']; + const lines = diffContent.split('\n'); + + lines.forEach((line) => { + const match = line.match(/^diff --git a\/(.+?) b\/(.+?)$/); + if (match) { + const filePath = match[1]; + const fileExtension = `.${filePath.split('.').pop()}`; + + if (relevantExtensions.includes(fileExtension)) { + const dirPath = path.dirname(filePath); + if (!relevantDirectories.includes(dirPath)) { + relevantDirectories.push(dirPath); + } + } + } + }); + + return relevantDirectories; +} + +// Function to run Gitleaks with directory paths +function runGitleaks(filePaths,repoRoot) { + return new Promise((resolve, reject) => { + const filesToCheck = filePaths + .map((filePath) => `"${path.resolve(repoRoot,filePath).replace(/\\/g, '/')}"`) + .join(' '); + console.log("filesToCheck:", filesToCheck); + + const configPath = path.resolve(__dirname, '../../../../gitleaks.toml').replace(/\\/g, '/'); + const reportPath = repoRoot + '/gitleaks_report.json'; + + const command = `gitleaks dir ${filesToCheck} --config="${configPath}" --report-format json --log-level debug --report-path="${reportPath}"`; + console.log(`Executing Gitleaks Command: ${command}`); + + cexec(command, (error, stdout, stderr) => { + if (error) { + // If leaks are found, handle the warning gracefully + console.log("stderrrrr:",stderr); + if (stderr.includes("leaks found")) { + console.warn("Leaks were found, but execution succeeded."); + resolve(true); // Consider this a successful run + } else { + console.error(`Error executing gitleaks: ${error.message}`); + reject(new Error(`Error executing gitleaks: ${error.message}`)); + } + } else { + resolve(false); + } + }); + }); +} + + + + +// Example usage in exec function +const exec = async (req, action) => { + const diffStep = action.steps.find((s) => s.stepName === 'diff'); + const step = new Step('checkforSecrets'); + const commitinfo = commitConfig.checkForSecrets; + + if (!commitinfo.enabled) { + action.addStep(step); + return action; + } + + if (diffStep && diffStep.content) { + const dirPaths = extractRelevantDirectories(diffStep.content); + const repoRoot = authorizedlist.find((item) => item.url === action.url).LocalRepoRoot; + + if (dirPaths.length > 0) { + try { + const res = await runGitleaks(dirPaths,repoRoot); + + + if (res) { + step.blocked = true; + step.blockedMessage = 'Sensitive secrets detected in the diff.'; + console.log('Sensitive secrets detected! Push blocked.'); + } else { + console.log('No sensitive secrets detected.'); + } + action.addStep(step); + } catch (err) { + console.error('Error during Gitleaks execution:', err); + } + } else { + console.log('No relevant directories found in the diff.'); + } + } else { + console.log('No diff content available.'); + } + + return action; +}; + +exec.displayName = 'checkforSecrets.exec'; +module.exports = { exec }; + + + diff --git a/src/proxy/processors/push-action/checkSensitiveData.js b/src/proxy/processors/push-action/checkSensitiveData.js new file mode 100644 index 000000000..51a50e440 --- /dev/null +++ b/src/proxy/processors/push-action/checkSensitiveData.js @@ -0,0 +1,185 @@ +const fs = require('fs'); +const csv = require('csv-parser'); +const XLSX = require('xlsx'); +const path = require('path'); +const Step = require('../../actions').Step; +const config = require('../../../config'); + +// const { exec: getDiffExec } = require('./getDiff'); +// Function to check for sensitive data patterns +const commitConfig = config.getCommitConfig(); +const authorizedlist = config.getAuthorisedList(); + +const checkForSensitiveData = (cell) => { + const sensitivePatterns = [ + /\d{3}-\d{2}-\d{4}/, // Social Security Number (SSN) + /\b\d{16}\b/, // Credit card numbers + /\b\d{5}-\d{4}\b/, // ZIP+4 codes + // Add more patterns as needed + ]; + return sensitivePatterns.some(pattern => { + if (pattern.test(String(cell))) { + console.log(`\x1b[31mDetected sensitive data: ${cell}\x1b[0m`); // Log the detected sensitive data in red + return true; + } + return false; + }); +}; +// Function to process CSV files +const processCSV = async (filePath) => { + return new Promise((resolve, reject) => { + let sensitiveDataFound = false; + fs.createReadStream(filePath) + .pipe(csv()) + .on('data', (row) => { + for (const [key, value] of Object.entries(row)) { + if (checkForSensitiveData(value)) { + console.log(`\x1b[33mSensitive data found in CSV: ${key}: ${value}\x1b[0m`); // Log in yellow + sensitiveDataFound = true; + } + } + }) + .on('end', () => { + if (!sensitiveDataFound) { + console.log('No sensitive data found in CSV.'); + } + resolve(sensitiveDataFound); // Resolve with the flag indicating if sensitive data was found + }) + .on('error', (err) => { + console.error(`Error reading CSV file: ${err.message}`); + reject(err); // Reject the promise on error + }); + }); +}; +// Function to process XLSX files +const processXLSX = async (filePath) => { + return new Promise((resolve, reject) => { + let sensitiveDataFound = false; + try { + const workbook = XLSX.readFile(filePath); + const sheetName = workbook.SheetNames[0]; + const sheet = workbook.Sheets[sheetName]; + const jsonData = XLSX.utils.sheet_to_json(sheet); + jsonData.forEach((row) => { + for (const [key, value] of Object.entries(row)) { + if (checkForSensitiveData(value)) { + console.log(`\x1b[33mSensitive data found in XLSX: ${key}: ${value}\x1b[0m`); // Log in yellow + sensitiveDataFound = true; + } + } + }); + if (!sensitiveDataFound) { + console.log('No sensitive data found in XLSX.'); + } + resolve(sensitiveDataFound); // Resolve with the flag indicating if sensitive data was found + } catch (error) { + console.error(`Error reading XLSX file: ${error.message}`); + reject(error); // Reject the promise on error + } + }); +}; +// Function to check for sensitive data in .log and .json files +const checkLogJsonFiles = async (filePath) => { + return new Promise((resolve, reject) => { + let sensitiveDataFound = false; + fs.readFile(filePath, 'utf8', (err, data) => { + if (err) { + console.error(`Error reading file ${filePath}: ${err.message}`); + return reject(err); + } + if (checkForSensitiveData(data)) { + console.log(`\x1b[Sensitive data found in ${filePath}\x1b[0m`); + sensitiveDataFound = true; + } + resolve(sensitiveDataFound); + }); + }); +}; +// Function to parse the file based on its extension +const parseFile = async (repoRoot, relativePath) => { + const filePath = path.join(repoRoot, relativePath); + + const ext = path.extname(filePath).toLowerCase(); + const FilestoCheck = commitConfig.diff.block.proxyFileTypes; + if(!FilestoCheck.includes(ext)){ + + console.log(`${ext} should be included in CommitConfig for proxy Check!`); + return false; + } + + switch (ext) { + case '.csv': + return await processCSV(filePath); + case '.xlsx': + return await processXLSX(filePath); + case '.log': + return await checkLogJsonFiles(filePath); + case '.json': + return await checkLogJsonFiles(filePath); + default: + // Skip unsupported file types without logging + return false; // Indicate that no sensitive data was found for unsupported types + } +}; +// Async exec function to handle actions +// Function to parse file paths from git diff content +const extractFilePathsFromDiff = (diffContent) => { + const filePaths = []; + const lines = diffContent.split('\n'); + + lines.forEach(line => { + const match = line.match(/^diff --git a\/(.+?) b\/(.+?)$/); + if (match) { + filePaths.push(match[1]); // Extract the file path from "a/" in the diff line + } + }); + + return filePaths; +}; + +const exec = async (req, action) => { + const diffStep = action.steps.find((s) => s.stepName === 'diff'); + const step = new Step('checksensitiveData'); + + if (diffStep && diffStep.content) { + console.log('Diff content:', diffStep.content); + + // Use the parsing function to get file paths + const filePaths = extractFilePathsFromDiff(diffStep.content); + + if (filePaths.length > 0) { + try { + const repoUrl = action.url; + const repo = authorizedlist.find((item) => item.url === repoUrl); + // console.log(repo); + const repoRoot = repo.LocalRepoRoot; + // console.log('my reporoot is ' + repoRoot); + + const sensitiveDataFound = await Promise.all( + filePaths.map((filePath) => parseFile(repoRoot, filePath)), + ); + const anySensitiveDataDetected = sensitiveDataFound.some((found) => found); + + if (anySensitiveDataDetected) { + step.blocked = true; + step.error = true; + step.errorMessage = 'Your push has been blocked due to sensitive data detection.'; + console.log(step.errorMessage); + } + } catch (error) { + console.error(`Error processing files: ${error.message}`); + } + } else { + console.log('No file paths provided in the diff step.'); + } + } else { + console.log('No diff content available.'); + } + action.addStep(step); + return action; // Returning action for testing purposes +}; + + + +exec.displayName = 'logFileChanges.exec'; +exports.exec = exec; \ No newline at end of file diff --git a/src/proxy/processors/push-action/getDiff.js b/src/proxy/processors/push-action/getDiff.js index 0a91161f4..09d69c182 100644 --- a/src/proxy/processors/push-action/getDiff.js +++ b/src/proxy/processors/push-action/getDiff.js @@ -2,6 +2,7 @@ const Step = require('../../actions').Step; const simpleGit = require('simple-git') + const exec = async (req, action) => { const step = new Step('diff'); diff --git a/src/proxy/processors/push-action/index.js b/src/proxy/processors/push-action/index.js index 72a97b33c..a0aa0d545 100644 --- a/src/proxy/processors/push-action/index.js +++ b/src/proxy/processors/push-action/index.js @@ -11,3 +11,8 @@ exports.checkCommitMessages = require('./checkCommitMessages').exec; exports.checkAuthorEmails = require('./checkAuthorEmails').exec; exports.checkUserPushPermission = require('./checkUserPushPermission').exec; exports.clearBareClone = require('./clearBareClone').exec; +exports.checkSensitiveData = require('./checkSensitiveData').exec; +exports.checkExifJpeg = require('./checkExifJpeg').exec; +exports.checkForAiMlusage = require('./checkForAiMlUsage').exec; +exports.checkForSecrets = require('./checkForSecrets').exec; +exports.checkCryptoImplementation = require('./checkCryptoImplementation').exec; diff --git a/test/CheckExif.test.js b/test/CheckExif.test.js new file mode 100644 index 000000000..209cc10bb --- /dev/null +++ b/test/CheckExif.test.js @@ -0,0 +1,79 @@ +const { exec } = require('../src/proxy/processors/push-action/checkExifJpeg.js'); +const sinon = require('sinon'); +const { Action } = require('../src/proxy/actions/Action.js'); +const { Step } = require('../src/proxy/actions/Step.js'); + + +describe('Check EXIF Data From Images', () => { + let logStub; + + + beforeEach(() => { + // Stub console.log and config.getCommitConfig for isolation in each test case + logStub = sinon.stub(console, 'log'); + + }); + + afterEach(() => { + // Restore stubs to avoid cross-test interference + logStub.restore(); + // configStub.restore(); + }); + + const createDiffContent = (filePaths) => { + // Creates diff-like content for each file path to simulate actual git diff output + return filePaths.map(filePath => `diff --git a/${filePath} b/${filePath}`).join('\n'); + }; + + it('Should block push when sensitive EXIF metadata is found (GPS)', async () => { + + + // Create action and step instances with test data that should trigger blocking + const action = new Action('action_id', 'push', 'create', Date.now(), 'owner/repo'); + const step = new Step('diff'); + + // Set content with sensitive EXIF metadata in the test image file + step.setContent(createDiffContent(['test/test_data/jpg/Sensitive_EXIF.jpg'])); + action.addStep(step); + + await exec(null, action); + + // Check that console.log was called with the blocking message + sinon.assert.calledWith(logStub, sinon.match(/Your push has been blocked due to sensitive EXIF metadata detection in an image/)); + }); + + it('Should block push when sensitive EXIF metadata is found (Camera Info)', async () => { + + + const action = new Action('action_id', 'push', 'create', Date.now(), 'owner/repo'); + const step = new Step('diff'); + + // Set content for a file that contains Camera-Info EXIF data + step.setContent(createDiffContent(['test/test_data/jpg/Sensitive_Data_EXIF_2.jpg'])); + action.addStep(step); + + await exec(null, action); + + // Assert blocking message was logged + sinon.assert.calledWith(logStub, sinon.match(/Your push has been blocked due to sensitive EXIF metadata detection in an image/)); + }); + + it('Should allow push when no sensitive EXIF metadata is found', async () => { + // Configure with no sensitive EXIF parameters + + + const action = new Action('action_id', 'push', 'create', Date.now(), 'owner/repo'); + const step = new Step('diff'); + + // Set content for a non-sensitive EXIF file + step.setContent(createDiffContent(['test/test_data/jpg/Not_Sensitive_EXIF.jpg'])); + action.addStep(step); + + await exec(null, action); + + // Ensure no blocking message was logged + sinon.assert.neverCalledWith(logStub, sinon.match(/Your push has been blocked due to sensitive EXIF metadata detection in an image/)); + }); + + +}); diff --git a/test/CheckSensitive.test.js b/test/CheckSensitive.test.js new file mode 100644 index 000000000..f51f79daa --- /dev/null +++ b/test/CheckSensitive.test.js @@ -0,0 +1,101 @@ +// const path = require('path'); +const { exec } = require('../src/proxy/processors/push-action/checkSensitiveData.js'); // Adjust path as necessary +const sinon = require('sinon'); +const {Action}=require('../src/proxy/actions/Action.js') +const {Step}=require('../src/proxy/actions/Step.js') + + +describe('Sensitive Data Detection', () => { + let logStub; + + beforeEach(() => { + logStub = sinon.stub(console, 'log'); // Stub console.log before each test + }); + + afterEach(() => { + logStub.restore(); // Restore console.log after each test + }); + + const createDiffContent = (filePaths) => { + // Format file paths in diff format + return filePaths.map(filePath => `diff --git a/${filePath} b/${filePath}`).join('\n'); + }; +// make sure the file types are added in proxyfiletypes in proxy.config.json + it('should detect sensitive data in CSV file and block execution', async () => { + const action = new Action('action_id', 'push', 'create', Date.now(), 'owner/repo'); + const step = new Step('diff'); + + // Create diff content simulating sensitive data in CSV + step.setContent(createDiffContent(['test/test_data/sensitive_data.csv'])); + action.addStep(step) + + await exec(null, action); + sinon.assert.calledWith(logStub, sinon.match(/Your push has been blocked due to sensitive data detection/)); + }); + + it('should detect sensitive data in XLSX file and block execution', async () => { + const action = new Action('action_id', 'push', 'create', Date.now(), 'owner/repo'); + const step = new Step('diff'); + step.setContent(createDiffContent(['test/test_data/sensitive_data2.xlsx'])); + action.addStep(step); + + await exec(null, action); + sinon.assert.calledWith(logStub, sinon.match(/Your push has been blocked due to sensitive data detection/)); + }); + + it('should detect sensitive data in a log file and block execution', async () => { + + const action = new Action('action_id', 'push', 'create', Date.now(), 'owner/repo'); + const step = new Step('diff'); + step.setContent(createDiffContent(['test/test_data/sensitive_data3.log'])); + action.addStep(step); + await exec(null, action); + sinon.assert.calledWith(logStub, sinon.match(/Your push has been blocked due to sensitive data detection/)); + }); + + it('should detect sensitive data in a JSON file and block execution', async () => { + + + const action = new Action('action_id', 'push', 'create', Date.now(), 'owner/repo'); + const step = new Step('diff'); + step.setContent(createDiffContent(['test/test_data/sensitive_data4.json'])); + action.addStep(step); + await exec(null, action); + sinon.assert.calledWith(logStub, sinon.match(/Your push has been blocked due to sensitive data detection/)); + }); + + it('should allow execution if no sensitive data is found', async () => { + + + const action = new Action('action_id', 'push', 'create', Date.now(), 'owner/repo'); + const step = new Step('diff'); + step.setContent(createDiffContent(['test_data/no_sensitive_data.txt'])); + action.addStep(step); + await exec(null, action); + sinon.assert.neverCalledWith(logStub, sinon.match(/Your push has been blocked due to sensitive data detection/)); + }); + + it('should allow execution for an empty file', async () => { + + + const action = new Action('action_id', 'push', 'create', Date.now(), 'owner/repo'); + const step = new Step('diff'); + step.setContent(createDiffContent(['test_data/empty_file.txt'])); + action.addStep(step); + await exec(null, action); + sinon.assert.neverCalledWith(logStub, sinon.match(/Your push has been blocked due to sensitive data detection/)); + }); + + it('should handle file-not-found scenario gracefully', async () => { + + const action = new Action('action_id', 'push', 'create', Date.now(), 'owner/repo'); + const step = new Step('diff'); + step.setContent(createDiffContent(['test_data/non_existent_file.txt'])); + action.addStep(step); + try { + await exec(null, action); + } catch (error) { + sinon.assert.match(error.message, /ENOENT: no such file or directory/); + } + }); +}); diff --git a/test/CreateExcel.js b/test/CreateExcel.js new file mode 100644 index 000000000..ea9f9af07 --- /dev/null +++ b/test/CreateExcel.js @@ -0,0 +1,19 @@ +const XLSX = require('xlsx'); +const fs = require('fs'); +const path = require('path'); +// Example data with sensitive information +const data = [ + { Name: "John Doe", SSN: "123-45-6789", Email: "john@example.com" }, + { Name: "Jane Smith", SSN: "987-65-4321", Email: "jane@example.com" } +]; +const worksheet = XLSX.utils.json_to_sheet(data); +const workbook = XLSX.utils.book_new(); +XLSX.utils.book_append_sheet(workbook, worksheet, "SensitiveData"); +// Create the path to the test_data directory +const testDataPath = path.join(__dirname, 'test_data'); // Ensure this points to the correct directory +// Create the test_data directory if it doesn't exist +if (!fs.existsSync(testDataPath)){ + fs.mkdirSync(testDataPath, { recursive: true }); // Using recursive to ensure all directories are created +} +// Write the Excel file to the test_data directory +XLSX.writeFile(workbook, path.join(testDataPath, 'sensitive_data2.xlsx')); \ No newline at end of file diff --git a/test/chain.test.js b/test/chain.test.js index 33d5750ac..153fe23aa 100644 --- a/test/chain.test.js +++ b/test/chain.test.js @@ -2,6 +2,7 @@ const chai = require('chai'); const sinon = require('sinon'); const { PluginLoader } = require('../src/plugin'); + chai.should(); const expect = chai.expect; @@ -19,13 +20,16 @@ const mockPushProcessors = { audit: sinon.stub(), checkRepoInAuthorisedList: sinon.stub(), checkCommitMessages: sinon.stub(), + checkCryptoImplementation: sinon.stub(), checkAuthorEmails: sinon.stub(), checkUserPushPermission: sinon.stub(), checkIfWaitingAuth: sinon.stub(), pullRemote: sinon.stub(), writePack: sinon.stub(), getDiff: sinon.stub(), + checkSensitiveData : sinon.stub(), clearBareClone: sinon.stub(), + checkEXIFJpeg : sinon.stub(), scanDiff: sinon.stub(), blockForAuth: sinon.stub(), }; @@ -33,12 +37,15 @@ mockPushProcessors.parsePush.displayName = 'parsePush'; mockPushProcessors.audit.displayName = 'audit'; mockPushProcessors.checkRepoInAuthorisedList.displayName = 'checkRepoInAuthorisedList'; mockPushProcessors.checkCommitMessages.displayName = 'checkCommitMessages'; +mockPushProcessors.checkCryptoImplementation.displayName = 'checkCryptoImplementation'; mockPushProcessors.checkAuthorEmails.displayName = 'checkAuthorEmails'; mockPushProcessors.checkUserPushPermission.displayName = 'checkUserPushPermission'; mockPushProcessors.checkIfWaitingAuth.displayName = 'checkIfWaitingAuth'; mockPushProcessors.pullRemote.displayName = 'pullRemote'; mockPushProcessors.writePack.displayName = 'writePack'; mockPushProcessors.getDiff.displayName = 'getDiff'; +mockPushProcessors.checkSensitiveData.displayName = 'checkSensitiveData'; +mockPushProcessors.checkEXIFJpeg.displayName = 'checkEXIFJpeg'; mockPushProcessors.clearBareClone.displayName = 'clearBareClone'; mockPushProcessors.scanDiff.displayName = 'scanDiff'; mockPushProcessors.blockForAuth.displayName = 'blockForAuth'; @@ -104,8 +111,11 @@ describe('proxy chain', function () { mockPushProcessors.parsePush.resolves(continuingAction); mockPushProcessors.checkRepoInAuthorisedList.resolves(continuingAction); mockPushProcessors.checkCommitMessages.resolves(continuingAction); + mockPushProcessors.checkEXIFJpeg.resolves(continuingAction); mockPushProcessors.checkAuthorEmails.resolves(continuingAction); mockPushProcessors.checkUserPushPermission.resolves(continuingAction); + mockPushProcessors.checkSensitiveData.resolves(continuingAction); + mockPushProcessors.checkCryptoImplementation.resolves(continuingAction); // this stops the chain from further execution mockPushProcessors.checkIfWaitingAuth.resolves({ type: 'push', continue: () => false, allowPush: false }); @@ -120,6 +130,9 @@ describe('proxy chain', function () { expect(mockPushProcessors.checkIfWaitingAuth.called).to.be.true; expect(mockPushProcessors.pullRemote.called).to.be.false; expect(mockPushProcessors.audit.called).to.be.true; + expect(mockPushProcessors.checkSensitiveData.called).to.be.false; + expect(mockPushProcessors.checkEXIFJpeg.called).to.be.false; + expect(mockPushProcessors.checkCryptoImplementation.called).to.be.true; expect(result.type).to.equal('push'); expect(result.allowPush).to.be.false; @@ -131,11 +144,16 @@ describe('proxy chain', function () { const continuingAction = { type: 'push', continue: () => true, allowPush: false }; mockPreProcessors.parseAction.resolves({ type: 'push' }); mockPushProcessors.parsePush.resolves(continuingAction); + mockPushProcessors.checkCryptoImplementation.resolves(continuingAction); mockPushProcessors.checkRepoInAuthorisedList.resolves(continuingAction); mockPushProcessors.checkCommitMessages.resolves(continuingAction); mockPushProcessors.checkAuthorEmails.resolves(continuingAction); mockPushProcessors.checkUserPushPermission.resolves(continuingAction); + mockPushProcessors.checkSensitiveData.resolves(continuingAction); + mockPushProcessors.checkEXIFJpeg.resolves(continuingAction); + // this stops the chain from further execution + mockPushProcessors.checkIfWaitingAuth.resolves({ type: 'push', continue: () => true, allowPush: true }); const result = await chain.executeChain(req); @@ -148,6 +166,9 @@ describe('proxy chain', function () { expect(mockPushProcessors.checkIfWaitingAuth.called).to.be.true; expect(mockPushProcessors.pullRemote.called).to.be.false; expect(mockPushProcessors.audit.called).to.be.true; + expect(mockPushProcessors.checkSensitiveData.called).to.be.false; + expect(mockPushProcessors.checkEXIFJpeg.called).to.be.false; + expect(mockPushProcessors.checkCryptoImplementation.called).to.be.true; expect(result.type).to.equal('push'); expect(result.allowPush).to.be.true; @@ -167,9 +188,13 @@ describe('proxy chain', function () { mockPushProcessors.pullRemote.resolves(continuingAction); mockPushProcessors.writePack.resolves(continuingAction); mockPushProcessors.getDiff.resolves(continuingAction); + mockPushProcessors.checkEXIFJpeg.resolves(continuingAction); mockPushProcessors.clearBareClone.resolves(continuingAction); mockPushProcessors.scanDiff.resolves(continuingAction); mockPushProcessors.blockForAuth.resolves(continuingAction); + mockPushProcessors.checkSensitiveData.resolves(continuingAction); + + mockPushProcessors.checkCryptoImplementation.resolves(continuingAction); const result = await chain.executeChain(req); @@ -183,10 +208,13 @@ describe('proxy chain', function () { expect(mockPushProcessors.pullRemote.called).to.be.true; expect(mockPushProcessors.writePack.called).to.be.true; expect(mockPushProcessors.getDiff.called).to.be.true; + expect(mockPushProcessors.checkEXIFJpeg.called).to.be.true; expect(mockPushProcessors.clearBareClone.called).to.be.true; expect(mockPushProcessors.scanDiff.called).to.be.true; expect(mockPushProcessors.blockForAuth.called).to.be.true; expect(mockPushProcessors.audit.called).to.be.true; + expect(mockPushProcessors.checkSensitiveData.called).to.be.true; + expect(mockPushProcessors.checkCryptoImplementation.called).to.be.true; expect(result.type).to.equal('push'); expect(result.allowPush).to.be.false; diff --git a/test/checkAiMlUsage.test.js b/test/checkAiMlUsage.test.js new file mode 100644 index 000000000..e8b126063 --- /dev/null +++ b/test/checkAiMlUsage.test.js @@ -0,0 +1,92 @@ +const { exec } = require('../src/proxy/processors/push-action/checkForAiMlUsage.js'); +const sinon = require('sinon'); +const { Action } = require('../src/proxy/actions/Action.js'); +const { Step } = require('../src/proxy/actions/Step.js'); + + +describe('Detect AI/ML usage from git diff', () => { + let logStub; + + beforeEach(() => { + // Stub console.log and config.getCommitConfig for isolation in each test case + logStub = sinon.stub(console, 'log'); + }); + + afterEach(() => { + // Restore stubs to avoid cross-test interference + logStub.restore(); + // configStub.restore(); + }); + + const createDiffContent = (filePaths) => { + // Creates diff-like content for each file path to simulate actual git diff output + return filePaths.map((filePath) => `diff --git a/${filePath} b/${filePath}`).join('\n'); + }; + + it('Block push if AI/ML file extensions detected', async () => { + // Create action and step instances with test data that should trigger blocking + const action = new Action('action_id', 'push', 'create', Date.now(), 'owner/repo'); + const step = new Step('diff'); + + const filePaths = [ + 'test/test_data/ai_test_data/model.h5', + 'test/test_data/ai_test_data/dataset.csv', + ]; + step.setContent(createDiffContent(filePaths)); + action.addStep(step); + + await exec(null, action); + + // Check that console.log was called with the blocking message + sinon.assert.calledWith( + logStub, + sinon.match( + /Your push has been blocked due to AI\/ML usage detection/, + ), + ); + }); + + it('Block push if AI/ML file content detected', async () => { + // Create action and step instances with test data that should trigger blocking + const action = new Action('action_id', 'push', 'create', Date.now(), 'owner/repo'); + const step = new Step('diff'); + + const filePaths = [ + 'test/test_data/ai_test_data/ai_script.py', + 'test/test_data/ai_test_data/ai_config.json', + ]; + step.setContent(createDiffContent(filePaths)); + action.addStep(step); + + await exec(null, action); + + // Check that console.log was called with the blocking message + sinon.assert.calledWith( + logStub, + sinon.match( + /Your push has been blocked due to AI\/ML usage detection/, + ), + ); + }); + + it('Allow push if no AI/ML usage is detected', async () => { + // Configure with no sensitive EXIF parameters + + const action = new Action('action_id', 'push', 'create', Date.now(), 'owner/repo'); + const step = new Step('diff'); + + const filePaths = ['test/test_data/ai_test_data/non_ai_script.py']; + step.setContent(createDiffContent(filePaths)); + action.addStep(step); + + await exec(null, action); + + // Ensure no blocking message was logged + sinon.assert.neverCalledWith( + logStub, + sinon.match( + /Your push has been blocked due to AI\/ML usage detection/, + ), + ); + }); +}); diff --git a/test/checkCryptoImplementation.test.js b/test/checkCryptoImplementation.test.js new file mode 100644 index 000000000..1d181c572 --- /dev/null +++ b/test/checkCryptoImplementation.test.js @@ -0,0 +1,223 @@ +const { expect } = require('chai'); +const { analyzeCodeForCrypto, exec } = require('../src/proxy/processors/push-action/checkCryptoImplementation.js'); + +describe('Crypto Implementation Check Plugin', () => { + describe('analyzeCodeForCrypto', () => { + it('should detect non-standard encryption algorithms', () => { + const testCode = ` + function customEncrypt(data) { + return data.split('').map(char => + String.fromCharCode(char.charCodeAt(0) ^ 0x7F) + ).join(''); + } + `; + + const issues = analyzeCodeForCrypto(testCode); + expect(issues).to.have.lengthOf.at.least(1); + expect(issues.some(i => i.type === 'non_standard_algorithm')).to.be.true; + }); + + it('should detect suspicious bit operations', () => { + const testCode = ` + function scrambleData(data) { + let result = ''; + for(let i = 0; i < data.length; i++) { + result += String.fromCharCode(data.charCodeAt(i) >>> 2); + } + return result; + } + `; + + const issues = analyzeCodeForCrypto(testCode); + expect(issues).to.have.lengthOf.at.least(1); + expect(issues.some(i => i.type === 'suspicious_operation')).to.be.true; + }); + + it('should detect suspicious variable names', () => { + const testCode = ` + const cipher = {}; + let salt = generateRandomBytes(16); + const iv = new Uint8Array(12); + `; + + const issues = analyzeCodeForCrypto(testCode); + expect(issues).to.have.lengthOf.at.least(3); + expect(issues.some(i => i.type === 'suspicious_variable')).to.be.true; + }); + + it('should not flag standard crypto library usage', () => { + const testCode = ` + const crypto = require('crypto'); + const cipher = crypto.createCipheriv('aes-256-gcm', key, iv); + `; + + const issues = analyzeCodeForCrypto(testCode); + expect(issues.filter(i => i.severity === 'high')).to.have.lengthOf(0); + }); + + it('should handle empty input', () => { + const issues = analyzeCodeForCrypto(''); + expect(issues).to.be.an('array').that.is.empty; + }); + + it('should handle null or undefined input', () => { + expect(analyzeCodeForCrypto(null)).to.be.an('array').that.is.empty; + expect(analyzeCodeForCrypto(undefined)).to.be.an('array').that.is.empty; + }); + + }); + + describe('exec', () => { + + it('should handle empty diff content', async () => { + const req = {}; + const action = { + commitData: [{ + hash: '123abc', + diff: '' + }], + addStep: function(step) { this.step = step; } + }; + + const result = await exec(req, action); + expect(result.step.error).to.be.false; + }); + + it('should handle undefined diff content', async () => { + const req = {}; + const action = { + commitData: [{ + hash: '123abc' + // diff is undefined + }], + addStep: function(step) { this.step = step; } + }; + + const result = await exec(req, action); + expect(result.step.error).to.be.false; + }); + + it('should handle empty commitData array', async () => { + const req = {}; + const action = { + commitData: [], + addStep: function(step) { this.step = step; } + }; + + const result = await exec(req, action); + expect(result.step.error).to.be.false; + }); + it('should block commits with non-standard crypto implementations', async () => { + const req = {}; + const action = { + commitData: [{ + hash: '123abc', + diff: ` + function customEncrypt(data) { + return data.split('').map(char => + String.fromCharCode(char.charCodeAt(0) ^ 0x7F) + ).join(''); + } + ` + }], + addStep: function(step) { this.step = step; } + }; + + const result = await exec(req, action); + expect(result.step.error).to.be.true; + }); + + it('should allow commits without crypto issues', async () => { + const req = {}; + const action = { + commitData: [{ + hash: '123abc', + diff: ` + function normalFunction() { + return 'Hello World'; + } + ` + }], + addStep: function(step) { this.step = step; } + }; + + const result = await exec(req, action); + expect(result.step.error).to.be.false; + }); + + it('should handle multiple commits', async () => { + const req = {}; + const action = { + commitData: [ + { + hash: '123abc', + diff: `function safe() { return true; }` + }, + { + hash: '456def', + diff: ` + function rot13(str) { + return str.replace(/[a-zA-Z]/g, c => + String.fromCharCode((c <= 'Z' ? 90 : 122) >= (c = c.charCodeAt(0) + 13) ? c : c - 26) + ); + } + ` + } + ], + addStep: function(step) { this.step = step; } + }; + + const result = await exec(req, action); + expect(result.step).to.have.property('error', true); +}); + + + it('should handle errors gracefully', async () => { + const req = {}; + const action = { + commitData: null, + addStep: function(step) { this.step = step; } + }; + + const result = await exec(req, action); + expect(result.step.error).to.be.true; + }); + }); + + describe('Pattern Detection', () => { + it('should detect various forms of XOR encryption', () => { + const testCases = [ + `function encrypt(a, b) { return a ^= b; }`, + `const result = data ^ key;`, + `function xor(plaintext, key) { return plaintext ^ key; }`, + `return char ^ 0xFF;` + ]; + + testCases.forEach(testCode => { + const issues = analyzeCodeForCrypto(testCode); + const hasXORIssue = issues.some(issue => + issue.type === 'suspicious_operation' || + issue.message.toLowerCase().includes('xor') + ); + expect(hasXORIssue, `Failed to detect XOR in: ${testCode}`).to.be.true; + }); + }); + + it('should detect custom hash implementations', () => { + const testCode = ` + function customHash(input) { + let hash = 0; + for(let i = 0; i < input.length; i++) { + hash = ((hash << 5) - hash) + input.charCodeAt(i); + hash = hash & hash; + } + return hash; + } + `; + + const issues = analyzeCodeForCrypto(testCode); + expect(issues).to.have.lengthOf.at.least(1); + expect(issues.some(i => i.severity === 'high')).to.be.true; + }); + }); +}); \ No newline at end of file diff --git a/test/test_data/GitleaksSampleData/sensitive_data.js b/test/test_data/GitleaksSampleData/sensitive_data.js new file mode 100644 index 000000000..395e80b55 --- /dev/null +++ b/test/test_data/GitleaksSampleData/sensitive_data.js @@ -0,0 +1,3 @@ +// File containing sensitive AWS Access Key +const secret = 'AKIAIOSFODNN9EXPLEAM'; // Example AWS access key +console.log(secret); \ No newline at end of file diff --git a/test/test_data/ai_test_data/ai_config.json b/test/test_data/ai_test_data/ai_config.json new file mode 100644 index 000000000..dfa43025f --- /dev/null +++ b/test/test_data/ai_test_data/ai_config.json @@ -0,0 +1,4 @@ +{ + "epochs": 100, + "learning_rate": 0.01 +} diff --git a/test/test_data/ai_test_data/ai_script.py b/test/test_data/ai_test_data/ai_script.py new file mode 100644 index 000000000..bf1ab1c2a --- /dev/null +++ b/test/test_data/ai_test_data/ai_script.py @@ -0,0 +1,4 @@ +import tensorflow as tf +model = tf.keras.models.Sequential() +model.add(tf.keras.layers.Dense(10, activation='relu')) +model.compile(optimizer='adam', loss='mse') diff --git a/test/test_data/ai_test_data/dataset.csv b/test/test_data/ai_test_data/dataset.csv new file mode 100644 index 000000000..3b56ac062 --- /dev/null +++ b/test/test_data/ai_test_data/dataset.csv @@ -0,0 +1,3 @@ +id,feature1,feature2,label +1,0.5,0.3,1 +2,0.6,0.2,0 diff --git a/test/test_data/ai_test_data/model.h5 b/test/test_data/ai_test_data/model.h5 new file mode 100644 index 000000000..118fc8cee --- /dev/null +++ b/test/test_data/ai_test_data/model.h5 @@ -0,0 +1 @@ +This is a dummy model file \ No newline at end of file diff --git a/test/test_data/ai_test_data/non_ai_script.py b/test/test_data/ai_test_data/non_ai_script.py new file mode 100644 index 000000000..f77c21295 --- /dev/null +++ b/test/test_data/ai_test_data/non_ai_script.py @@ -0,0 +1 @@ +print("Hello World") # No AI/ML content \ No newline at end of file diff --git a/test/test_data/jpg/Not_Sensitive_EXIF.jpg b/test/test_data/jpg/Not_Sensitive_EXIF.jpg new file mode 100644 index 000000000..2d6a14bda Binary files /dev/null and b/test/test_data/jpg/Not_Sensitive_EXIF.jpg differ diff --git a/test/test_data/jpg/Not_Sensitive_EXIF_2.jpg b/test/test_data/jpg/Not_Sensitive_EXIF_2.jpg new file mode 100644 index 000000000..131dee358 Binary files /dev/null and b/test/test_data/jpg/Not_Sensitive_EXIF_2.jpg differ diff --git a/test/test_data/jpg/Sensitive_Data_EXIF_2.jpg b/test/test_data/jpg/Sensitive_Data_EXIF_2.jpg new file mode 100644 index 000000000..8cf1e5ca4 Binary files /dev/null and b/test/test_data/jpg/Sensitive_Data_EXIF_2.jpg differ diff --git a/test/test_data/jpg/Sensitive_EXIF.jpg b/test/test_data/jpg/Sensitive_EXIF.jpg new file mode 100644 index 000000000..0508a2a0e Binary files /dev/null and b/test/test_data/jpg/Sensitive_EXIF.jpg differ diff --git a/test/test_data/sensitveDatalikecsv/sensitive_data.csv b/test/test_data/sensitveDatalikecsv/sensitive_data.csv new file mode 100644 index 000000000..d0381fa03 --- /dev/null +++ b/test/test_data/sensitveDatalikecsv/sensitive_data.csv @@ -0,0 +1,3 @@ +Name,SSN,Email +John Doe,123-45-6789,john@example.com +Jane Smith,987-65-4321,jane@example.com diff --git a/test/test_data/sensitveDatalikecsv/sensitive_data2.xlsx b/test/test_data/sensitveDatalikecsv/sensitive_data2.xlsx new file mode 100644 index 000000000..3c9634cc7 Binary files /dev/null and b/test/test_data/sensitveDatalikecsv/sensitive_data2.xlsx differ diff --git a/test/test_data/sensitveDatalikecsv/sensitive_data4.json b/test/test_data/sensitveDatalikecsv/sensitive_data4.json new file mode 100644 index 000000000..50217f695 --- /dev/null +++ b/test/test_data/sensitveDatalikecsv/sensitive_data4.json @@ -0,0 +1,4 @@ +{ + "username": "johndoe", + "ssn": "123-45-6789" +}