generic.go 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. package rules
  2. import (
  3. regexp "github.com/wasilibs/go-re2"
  4. "github.com/zricethezav/gitleaks/v8/cmd/generate/config/utils"
  5. "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
  6. "github.com/zricethezav/gitleaks/v8/config"
  7. )
  8. func GenericCredential() *config.Rule {
  9. // define rule
  10. r := config.Rule{
  11. RuleID: "generic-api-key",
  12. Description: "Detected a Generic API Key, potentially exposing access to various services and sensitive operations.",
  13. Regex: utils.GenerateSemiGenericRegex([]string{
  14. "access",
  15. "auth",
  16. `(?-i:[Aa]pi|API)`,
  17. "credential",
  18. "creds",
  19. "key",
  20. "passwd",
  21. "password",
  22. "secret",
  23. "token",
  24. }, `[\w.=-]{10,150}`, true),
  25. Keywords: []string{
  26. "access",
  27. "api",
  28. "auth",
  29. "key",
  30. "credential",
  31. "creds",
  32. "passwd",
  33. "password",
  34. "secret",
  35. "token",
  36. },
  37. Entropy: 3.5,
  38. Allowlists: []config.Allowlist{
  39. {
  40. Description: "Allowlist for Generic API Keys",
  41. MatchCondition: config.AllowlistMatchOr,
  42. RegexTarget: "match",
  43. Regexes: []*regexp.Regexp{
  44. regexp.MustCompile(`(?i)(` +
  45. // Access
  46. `accessor` +
  47. `|access[_.-]?id` +
  48. // API
  49. `|api[_.-]?(version|id)` + // version/id -> not a secret
  50. `|rapid|capital` + // common words containing "api"
  51. `|[a-z0-9-]*?api[a-z0-9-]*?:jar:` + // Maven META-INF dependencies that contain "api" in the name.
  52. // Auth
  53. `|author` +
  54. `|X-MS-Exchange-Organization-Auth` + // email header
  55. `|Authentication-Results` + // email header
  56. // Credentials
  57. `|(credentials?[_.-]?id|withCredentials)` + // Jenkins plugins
  58. // Key
  59. `|(bucket|foreign|hot|natural|primary|schema|sequence)[_.-]?key` +
  60. `|key[_.-]?(alias|board|code|ring|selector|size|stone|storetype|word|up|down|left|right)` +
  61. `|key(store|tab)[_.-]?(file|path)` +
  62. `|issuerkeyhash` + // part of ssl cert
  63. `|(?-i:[DdMm]onkey|[DM]ONKEY)|keying` + // common words containing "key"
  64. // Secret
  65. `|(secret)[_.-]?name` + // name of e.g. env variable
  66. `|UserSecretsId` + // https://learn.microsoft.com/en-us/aspnet/core/security/app-secrets?view=aspnetcore-8.0&tabs=linux
  67. // Token
  68. // General
  69. `|(api|credentials|token)[_.-]?(endpoint|ur[il])` +
  70. `|public[_.-]?(key|token)` + // public key -> not a secret
  71. `|(key|token)[_.-]?file` +
  72. `)`),
  73. },
  74. StopWords: DefaultStopWords,
  75. },
  76. },
  77. }
  78. // validate
  79. tps := utils.GenerateSampleSecrets("generic", "CLOJARS_34bf0e88955ff5a1c328d6a7491acc4f48e865a7b8dd4d70a70749037443") //gitleaks:allow
  80. tps = append(tps, utils.GenerateSampleSecrets("generic", "Zf3D0LXCM3EIMbgJpUNnkRtOfOueHznB")...)
  81. tps = append(tps,
  82. // Access
  83. `'access_token': 'eyJ0eXAioiJKV1slS3oASx=='`,
  84. // API
  85. `some_api_token_123 = "`+newPlausibleSecret(`[a-zA-Z0-9]{60}`)+`"`,
  86. // Auth
  87. // Credentials
  88. `"credentials" : "0afae57f3ccfd9d7f5767067bc48b30f719e271ba470488056e37ab35d4b6506"`,
  89. `creds = `+newPlausibleSecret(`[a-zA-Z0-9]{30}`),
  90. // Key
  91. `private-key: `+newPlausibleSecret(`[a-zA-Z0-9\-_.=]{100}`),
  92. // Password
  93. `passwd = `+newPlausibleSecret(`[a-zA-Z0-9\-_.=]{30}`),
  94. // TODO: `ID=dbuser;password=` + newPlausibleSecret(`[a-zA-Z0-9+/]{30}={0,3}`) + `;"`,
  95. // Secret
  96. `"client_secret" : "6da89121079f83b2eb6acccf8219ea982c3d79bccc3e9c6a85856480661f8fde",`,
  97. `mySecretString=`+newPlausibleSecret(`[a-zA-Z0-9]{30}`),
  98. `todo_secret_do_not_commit = `+newPlausibleSecret(`[a-zA-Z0-9]{30}`),
  99. // Token
  100. utils.GenerateSampleSecret("generic", "CLOJARS_34bf0e88955ff5a1c328d6a7491acc4f48e865a7b8dd4d70a70749037443"), //gitleaks:allow
  101. utils.GenerateSampleSecret("generic", "Zf3D0LXCM3EIMbgJpUNnkRtOfOueHznB"),
  102. )
  103. fps := []string{
  104. // Access
  105. `"accessor":"rA1wk0Y45YCufyfq",`,
  106. `report_access_id: e8e4df51-2054-49b0-ab1c-516ac95c691d`,
  107. // API
  108. `this.ultraPictureBox1.Name = "ultraPictureBox1";`,
  109. `rapidstring:marm64-uwp=fail`,
  110. `event-bus-message-api:rc0.15.0_20231217_1420-SNAPSHOT'`,
  111. `COMMUNICATION_API_VERSION=rc0.13.0_20230412_0712-SNAPSHOT`,
  112. `MantleAPI_version=9a038989604e8da62ecddbe2094b16ce1b778be1`,
  113. `[DEBUG] org.slf4j.slf4j-api:jar:1.7.8.:compile (version managed from default)`,
  114. `[DEBUG] org.neo4j.neo4j-graphdb-api:jar:3.5.12:test`,
  115. `apiUrl=apigee.corpint.com`,
  116. // TODO: Jetbrains IML files (requires line-level allowlist).
  117. // `<orderEntry type="library" scope="PROVIDED" name="Maven: org.apache.directory.api:api-asn1-api:1.0.0-M20" level="projcet" />`
  118. // Auth
  119. `author = "james.fake@ymail.com",`,
  120. `X-MS-Exchange-Organization-AuthSource: sm02915.int.contoso.com`,
  121. `Authentication-Results: 5h.ca.iphmx.com`,
  122. // Credentials
  123. `withCredentials([usernamePassword(credentialsId: '29f63271-dc2f-4734-8221-5b31b5169bac', usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD')]) {`,
  124. `credentialsId: 'ff083f76-7804-4ef1-80e4-fe975bb9141b'`,
  125. `jobCredentialsId: 'f4aeb6bc-2a25-458a-8111-9be9e502c0e7'`,
  126. ` "credentialId": "B9mTcFSck2LzJO2S3ols63",`,
  127. `environment {
  128. CREDENTIALS_ID = "K8S_CRED"
  129. }`,
  130. `dev.credentials.url=dev-lb1.api.f4ke.com:5215`,
  131. // Key
  132. `keyword: "Befaehigung_P2"`,
  133. `public_key = "9Cnzj4p4WGeKLs1Pt8QuKUpRKfFLfRYC9AIKjbJTWit"`,
  134. `monkeys-audio:mx64-uwp=fail`,
  135. `primaryKey=` + newPlausibleSecret(`[a-zA-Z0-9\-_.=]{30}`),
  136. `foreignKey=` + newPlausibleSecret(`[a-zA-Z0-9\-_.=]{30}`),
  137. `key_down_event=` + newPlausibleSecret(`[a-zA-Z0-9\-_.=]{30}`),
  138. `issuerKeyHash=` + newPlausibleSecret(`[a-zA-Z0-9\-_.=]{30}`),
  139. `<entry key="jetbrains.mps.v8_elimination" value="executed" />`,
  140. `minisat-master-keying:x64-uwp=fail`,
  141. `IceSSL.KeyFile=s_rsa1024_priv.pem`,
  142. `"bucket_key": "SalesResults-1.2"`,
  143. // `<TAR key="REF_ID_923.properties" value="/opts/config/alias/"/>`,
  144. `<key tag="SecurityIdentifier" name="SecurityIdentifier" type="STRING" />`,
  145. // `packageKey":` + newPlausibleSecret(`[a-zA-Z0-9\-_.=]{30}`),
  146. `schemaKey = 'DOC_Vector_5_32'`,
  147. `sequenceKey = "18"`,
  148. `app.keystore.file=env/cert.p12`,
  149. `-DKEYTAB_FILE=/tmp/app.keytab`,
  150. ` doc.Security.KeySize = PdfEncryptionKeySize.Key128Bit;`,
  151. `o.keySelector=n,o.haKey=!1,`,
  152. // TODO: Requires line-level allowlists.
  153. // `<add key="SchemaTable" value="G:\SchemaTable.xml" />`,
  154. // `secret:
  155. // secretName: app-decryption-secret
  156. // items:
  157. // - key: app-k8s.yml
  158. // path: app-k8s.yml`,
  159. // TODO: https://learn.microsoft.com/en-us/windows/apps/design/style/xaml-theme-resources
  160. // `<Color x:Key="NormalBrushGradient1">#FFBAE4FF</Color>`,
  161. // Password
  162. `password combination.
  163. R5: Regulatory--21`,
  164. `PuttyPassword=0`,
  165. // Secret
  166. `LLM_SECRET_NAME = "NEXUS-GPT4-API-KEY"`,
  167. ` <UserSecretsId>79a3edd0-2092-40a2-a04d-dcb46d5ca9ed</UserSecretsId>`,
  168. // Token
  169. ` access_token_url='https://github.com/login/oauth/access_token',`,
  170. `publicToken = "9Cnzj4p4WGeKLs1Pt8QuKUpRKfFLfRYC9AIKjbJTWit"`,
  171. `<SourceFile SourceLocation="F:\Extracts\" TokenFile="RTL_INST_CODE.cer">`,
  172. // TODO: `TOKEN_AUDIENCE = "25872395-ed3a-4703-b647-22ec53f3683c"`,
  173. // General
  174. `clientId = "73082700-1f09-405b-80d0-3131bfd6272d"`,
  175. }
  176. return utils.Validate(r, tps, fps)
  177. }
  178. func newPlausibleSecret(regex string) string {
  179. allowList := config.Allowlist{StopWords: DefaultStopWords}
  180. // attempt to generate a random secret,
  181. // retrying until it contains at least one digit and no stop words
  182. // TODO: currently the DefaultStopWords list contains many short words,
  183. // so there is a significant chance of generating a secret that contains a stop word
  184. for {
  185. secret := secrets.NewSecret(regex)
  186. if !regexp.MustCompile(`[1-9]`).MatchString(secret) {
  187. continue
  188. }
  189. if allowList.ContainsStopWord(secret) {
  190. continue
  191. }
  192. return secret
  193. }
  194. }