diff --git a/crates/biome_analyze/src/rule.rs b/crates/biome_analyze/src/rule.rs index 1b7dc60e1af0..3f1bce27efbc 100644 --- a/crates/biome_analyze/src/rule.rs +++ b/crates/biome_analyze/src/rule.rs @@ -118,7 +118,7 @@ pub enum RuleSource { EslintTypeScript(&'static str), /// Rules from [Eslint Plugin Unicorn](https://github.com/sindresorhus/eslint-plugin-unicorn) EslintUnicorn(&'static str), - /// Rules from [Eslint Plugin Unused Imports](https://github.com/sweepline/eslint-plugin-unused-imports) + /// Rules from [Eslint Plugin Unused Imports](https://github.com/sweepline/eslint-plugin-unused-imports) EslintUnusedImports(&'static str), /// Rules from [Eslint Plugin Mysticatea](https://github.com/mysticatea/eslint-plugin) EslintMysticatea(&'static str), @@ -130,6 +130,8 @@ pub enum RuleSource { EslintNext(&'static str), /// Rules from [Stylelint](https://github.com/stylelint/stylelint) Stylelint(&'static str), + /// Rules from [Eslint Plugin No Secrets](https://github.com/nickdeis/eslint-plugin-no-secrets) + EslintNoSecrets(&'static str), } impl PartialEq for RuleSource { @@ -162,6 +164,7 @@ impl std::fmt::Display for RuleSource { Self::EslintN(_) => write!(f, "eslint-plugin-n"), Self::EslintNext(_) => write!(f, "@next/eslint-plugin-next"), Self::Stylelint(_) => write!(f, "Stylelint"), + Self::EslintNoSecrets(_) => write!(f, "eslint-plugin-no-secrets"), } } } @@ -211,6 +214,7 @@ impl RuleSource { | Self::EslintBarrelFiles(rule_name) | Self::EslintN(rule_name) | Self::EslintNext(rule_name) + | Self::EslintNoSecrets(rule_name) | Self::Stylelint(rule_name) => rule_name, } } @@ -237,6 +241,7 @@ impl RuleSource { Self::EslintN(rule_name) => format!("n/{rule_name}"), Self::EslintNext(rule_name) => format!("@next/{rule_name}"), Self::Stylelint(rule_name) => format!("stylelint/{rule_name}"), + Self::EslintNoSecrets(rule_name) => format!("no-secrets/{rule_name}"), } } @@ -263,6 +268,7 @@ impl RuleSource { Self::EslintN(rule_name) => format!("https://github.com/eslint-community/eslint-plugin-n/blob/master/docs/rules/{rule_name}.md"), Self::EslintNext(rule_name) => format!("https://nextjs.org/docs/messages/{rule_name}"), Self::Stylelint(rule_name) => format!("https://github.com/stylelint/stylelint/blob/main/lib/rules/{rule_name}/README.md"), + Self::EslintNoSecrets(_) => "https://github.com/nickdeis/eslint-plugin-no-secrets/blob/master/README.md".to_string(), } } diff --git a/crates/biome_js_analyze/src/lint/nursery/no_secrets.rs b/crates/biome_js_analyze/src/lint/nursery/no_secrets.rs index 6504a2bd1dda..279a061d05fb 100644 --- a/crates/biome_js_analyze/src/lint/nursery/no_secrets.rs +++ b/crates/biome_js_analyze/src/lint/nursery/no_secrets.rs @@ -10,14 +10,58 @@ use regex::Regex; use std::sync::LazyLock; +use biome_deserialize_macros::Deserializable; +use serde::{Deserialize, Serialize}; + // TODO: Try to get this to work in JavaScript comments as well declare_lint_rule! { /// Disallow usage of sensitive data such as API keys and tokens. /// /// This rule checks for high-entropy strings and matches common patterns - /// for secrets, such as AWS keys, Slack tokens, and private keys. + /// for secrets, including AWS keys, Slack tokens, and private keys. + /// It aims to help users identify immediate potential secret leaks in their codebase, + /// especially for those who may not be aware of the risks associated with + /// sensitive data exposure. + /// + /// ## Detected Secrets + /// + /// The following list contains the patterns we detect: + /// + /// - **JSON Web Token (JWT)**: Tokens in the format of `ey...` + /// - **Base64-encoded JWT**: Base64-encoded JWT tokens with various parameters (alg, aud, iss, etc.) + /// - **Slack Token**: Tokens such as `xox[baprs]-...` + /// - **Slack Webhook URL**: URLs like `https://hooks.slack.com/services/...` + /// - **GitHub Token**: GitHub tokens with lengths between 35-40 characters + /// - **Twitter OAuth Token**: Twitter OAuth tokens with lengths between 35-44 characters + /// - **Facebook OAuth Token**: Facebook OAuth tokens with possible lengths up to 42 characters + /// - **Google OAuth Token**: Google OAuth tokens in the format `ya29...` + /// - **AWS API Key**: Keys that begin with `AKIA` followed by 16 alphanumeric characters + /// - **Passwords in URLs**: Passwords included in URL credentials (`protocol://user:pass@...`) + /// - **Google Service Account**: JSON structure with the service-account identifier + /// - **Twilio API Key**: API keys starting with `SK...` followed by 32 characters + /// - **RSA Private Key**: Key blocks that start with `-----BEGIN RSA PRIVATE KEY-----` + /// - **OpenSSH Private Key**: Key blocks that start with `-----BEGIN OPENSSH PRIVATE KEY-----` + /// - **DSA Private Key**: Key blocks that start with `-----BEGIN DSA PRIVATE KEY-----` + /// - **EC Private Key**: Key blocks that start with `-----BEGIN EC PRIVATE KEY-----` + /// - **PGP Private Key Block**: Key blocks that start with `-----BEGIN PGP PRIVATE KEY BLOCK-----` + /// + /// ## Entropy Check + /// + /// In addition to detecting the above patterns, we also employ a **string entropy checker** to catch potential secrets based on their entropy (randomness). The entropy checker is configurable through the `Options`, allowing customization of thresholds for string entropy to fine-tune detection and minimize false positives. + /// + /// ## Disclaimer + /// + /// While this rule helps with most common cases, it is not intended to handle all of them. + /// Therefore, always review your code carefully and consider implementing additional security + /// measures, such as automated secret scanning in your CI/CD and git pipeline. /// - /// While this rule is helpful, it's not infallible. Always review your code carefully and consider implementing additional security measures like automated secret scanning in your CI/CD and git pipeline, such as GitGuardian or GitHub protections. + /// ## Recommendations + /// + /// Some recommended tools for more comprehensive secret detection include: + /// - [SonarQube](https://www.sonarsource.com/products/sonarqube/downloads/): Clean Code scanning solution with a secret scanner (Community version). + /// - [Gitleaks](https://github.com/gitleaks/gitleaks/): A mature secret scanning tool. + /// - [Trufflehog](https://github.com/trufflesecurity/trufflehog): A tool for finding secrets in git history. + /// - [Sensleak](https://github.com/crates-pro/sensleak-rs): A Rust-based solution for secret detection. /// /// ## Examples /// @@ -37,7 +81,7 @@ declare_lint_rule! { name: "noSecrets", language: "js", recommended: false, - sources: &[RuleSource::Eslint("no-secrets/no-secrets")], + sources: &[RuleSource::EslintNoSecrets("no-secrets")], source_kind: RuleSourceKind::Inspired, } } @@ -46,7 +90,7 @@ impl Rule for NoSecrets { type Query = Ast; type State = &'static str; type Signals = Option; - type Options = (); + type Options = NoSecretsOptions; fn run(ctx: &RuleContext) -> Self::Signals { let node = ctx.query(); @@ -57,11 +101,17 @@ impl Rule for NoSecrets { return None; } + let has_spaces = text.contains(' '); + for sensitive_pattern in SENSITIVE_PATTERNS.iter() { if text.len() < sensitive_pattern.min_len { continue; } + if has_spaces && !sensitive_pattern.allows_spaces { + continue; + } + let matched = match &sensitive_pattern.pattern { Pattern::Regex(re) => re.is_match(text), Pattern::Contains(substring) => text.contains(substring), @@ -72,11 +122,15 @@ impl Rule for NoSecrets { } } - if is_high_entropy(text) { - Some("The string has a high entropy value") - } else { - None + if is_path(text) { + return None; } + + let entropy_threshold = ctx + .options() + .entropy_threshold + .unwrap_or(DEFAULT_HIGH_ENTROPY_THRESHOLD); + detect_secret(text, &entropy_threshold) } fn diagnostic(ctx: &RuleContext, state: &Self::State) -> Option { @@ -92,16 +146,37 @@ impl Rule for NoSecrets { "Storing secrets in source code is a security risk. Consider the following steps:" "\n1. Remove the secret from your code. If you've already committed it, consider removing the commit entirely from your git tree." "\n2. If needed, use environment variables or a secure secret management system to store sensitive data." - "\n3. If this is a false positive, consider adding an inline disable comment." + "\n3. If this is a false positive, consider adding an inline disable comment, or tweak the entropy threshold. See options ""in our docs." + "\nThis rule only catches basic vulnerabilities. For more robust, proper solutions, check out our recommendations at: ""https://biomejs.dev/linter/rules/no-secrets/#recommendations" }) ) } } -const HIGH_ENTROPY_THRESHOLD: f64 = 4.5; +#[derive(Clone, Debug, Default, Deserialize, Deserializable, Eq, PartialEq, Serialize)] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +pub struct NoSecretsOptions { + /// Set entropy threshold (default is 41). + entropy_threshold: Option, +} + +fn is_path(text: &str) -> bool { + // Check for common path indicators + text.starts_with("./") || text.starts_with("../") +} + +const DEFAULT_HIGH_ENTROPY_THRESHOLD: u16 = 41; + +// Known sensitive patterns start here +static JWT_REGEX: LazyLock = LazyLock::new(|| { + Regex::new(r#"\b(ey[a-zA-Z0-9]{17,}\.ey[a-zA-Z0-9\/\\_-]{17,}\.(?:[a-zA-Z0-9\/\\_-]{10,}={0,2})?)(?:['|\"|\n|\r|\s|\x60|;]|$)"#).unwrap() +}); + +static JWT_BASE64_REGEX: LazyLock = LazyLock::new(|| { + Regex::new(r#"\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}"#).unwrap() +}); -// Workaround: Since I couldn't figure out how to declare them inline, -// declare the LazyLock patterns separately static SLACK_TOKEN_REGEX: LazyLock = LazyLock::new(|| Regex::new(r"xox[baprs]-([0-9a-zA-Z]{10,48})?").unwrap()); @@ -121,13 +196,6 @@ static TWITTER_OAUTH_REGEX: LazyLock = static FACEBOOK_OAUTH_REGEX: LazyLock = LazyLock::new(|| Regex::new(r#"[fF][aA][cC][eE][bB][oO][oO][kK].*(?:.{0,42})"#).unwrap()); -static HEROKU_API_KEY_REGEX: LazyLock = LazyLock::new(|| { - Regex::new( - r"[hH][eE][rR][oO][kK][uU].*[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}", - ) - .unwrap() -}); - static PASSWORD_IN_URL_REGEX: LazyLock = LazyLock::new(|| { Regex::new(r#"[a-zA-Z]{3,10}://[^/\s:@]{3,20}:[^/\s:@]{3,20}@.{1,100}['"\s]"#).unwrap() }); @@ -155,119 +223,282 @@ struct SensitivePattern { pattern: Pattern, comment: &'static str, min_len: usize, + allows_spaces: bool, } static SENSITIVE_PATTERNS: &[SensitivePattern] = &[ + SensitivePattern { + pattern: Pattern::Regex(&JWT_REGEX), + comment: "JSON Web Token (JWT)", + min_len: 100, + allows_spaces: false, + }, + SensitivePattern { + pattern: Pattern::Regex(&JWT_BASE64_REGEX), + comment: "Base64-encoded JWT", + min_len: 100, + allows_spaces: false, + }, SensitivePattern { pattern: Pattern::Regex(&SLACK_TOKEN_REGEX), comment: "Slack Token", min_len: 32, + allows_spaces: false, }, SensitivePattern { pattern: Pattern::Regex(&SLACK_WEBHOOK_REGEX), comment: "Slack Webhook", min_len: 24, + allows_spaces: false, }, SensitivePattern { pattern: Pattern::Regex(&GITHUB_TOKEN_REGEX), comment: "GitHub", min_len: 35, + allows_spaces: false, }, SensitivePattern { pattern: Pattern::Regex(&TWITTER_OAUTH_REGEX), comment: "Twitter OAuth", min_len: 35, + allows_spaces: false, }, SensitivePattern { pattern: Pattern::Regex(&FACEBOOK_OAUTH_REGEX), comment: "Facebook OAuth", min_len: 32, + allows_spaces: false, }, SensitivePattern { pattern: Pattern::Regex(&GOOGLE_OAUTH_REGEX), comment: "Google OAuth", min_len: 24, + allows_spaces: false, }, SensitivePattern { pattern: Pattern::Regex(&AWS_API_KEY_REGEX), comment: "AWS API Key", min_len: 16, - }, - SensitivePattern { - pattern: Pattern::Regex(&HEROKU_API_KEY_REGEX), - comment: "Heroku API Key", - min_len: 12, + allows_spaces: false, }, SensitivePattern { pattern: Pattern::Regex(&PASSWORD_IN_URL_REGEX), comment: "Password in URL", min_len: 14, + allows_spaces: false, }, SensitivePattern { pattern: Pattern::Regex(&GOOGLE_SERVICE_ACCOUNT_REGEX), comment: "Google (GCP) Service-account", min_len: 14, + allows_spaces: true, }, SensitivePattern { pattern: Pattern::Regex(&TWILIO_API_KEY_REGEX), comment: "Twilio API Key", min_len: 32, + allows_spaces: false, }, SensitivePattern { pattern: Pattern::Contains("-----BEGIN RSA PRIVATE KEY-----"), comment: "RSA Private Key", min_len: 64, + allows_spaces: true, }, SensitivePattern { pattern: Pattern::Contains("-----BEGIN OPENSSH PRIVATE KEY-----"), comment: "SSH (OPENSSH) Private Key", min_len: 64, + allows_spaces: true, }, SensitivePattern { pattern: Pattern::Contains("-----BEGIN DSA PRIVATE KEY-----"), comment: "SSH (DSA) Private Key", min_len: 64, + allows_spaces: true, }, SensitivePattern { pattern: Pattern::Contains("-----BEGIN EC PRIVATE KEY-----"), comment: "SSH (EC) Private Key", min_len: 64, + allows_spaces: true, }, SensitivePattern { pattern: Pattern::Contains("-----BEGIN PGP PRIVATE KEY BLOCK-----"), comment: "PGP Private Key Block", min_len: 64, + allows_spaces: true, }, ]; +const MIN_PATTERN_LEN: usize = 14; + +// Known safe patterns start here +static BASE64_REGEX: LazyLock = LazyLock::new(|| { + Regex::new(r"^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$").unwrap() +}); +static URL_REGEX: LazyLock = + LazyLock::new(|| Regex::new(r"^https?://[a-zA-Z0-9.-]+(/[a-zA-Z0-9./_-]*)?$").unwrap()); +static RELATIVE_PATH_REGEX: LazyLock = + LazyLock::new(|| Regex::new(r"^(?:\.\./|\./|[a-zA-Z0-9_-]+)/?$").unwrap()); +static UNIX_PATH_REGEX: LazyLock = LazyLock::new(|| Regex::new(r"^(/[^/]+)+/?$").unwrap()); +static WINDOWS_PATH_REGEX: LazyLock = + LazyLock::new(|| Regex::new(r"^[a-zA-Z]:\\(?:[^\\]+\\?)*$").unwrap()); +static EMAIL_REGEX: LazyLock = + LazyLock::new(|| Regex::new(r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$").unwrap()); +static PHONE_REGEX: LazyLock = LazyLock::new(|| Regex::new(r"^\+?[1-9]\d{1,14}$").unwrap()); // E.164 format + +// Combine all known safe patterns into a single list +static KNOWN_SAFE_PATTERNS: &[&LazyLock] = &[ + &BASE64_REGEX, + &URL_REGEX, + &RELATIVE_PATH_REGEX, + &UNIX_PATH_REGEX, + &WINDOWS_PATH_REGEX, + &EMAIL_REGEX, + &PHONE_REGEX, +]; + +fn is_known_safe_pattern(data: &str) -> bool { + for pattern in KNOWN_SAFE_PATTERNS { + if pattern.is_match(data) { + return true; + } + } + false +} + +fn detect_secret(data: &str, entropy_threshold: &u16) -> Option<&'static str> { + if is_known_safe_pattern(data) { + return None; + } -const MIN_PATTERN_LEN: usize = 12; + let tokens = data + .split([' ', '\t', '\n', '.', ',', ';', ':', '/', '-', '_', '@']) + .filter(|s| !s.is_empty()); -fn is_high_entropy(text: &str) -> bool { - let entropy = calculate_shannon_entropy(text); - entropy > HIGH_ENTROPY_THRESHOLD // TODO: Make this optional, or controllable + for token in tokens { + if token.len() >= MIN_PATTERN_LEN { + if is_known_safe_pattern(token) { + continue; + } + + let entropy = + calculate_entropy_with_case_and_classes(token, *entropy_threshold as f64, 15.0); + if (entropy as u16) > *entropy_threshold { + return Some("Detected high entropy string"); + } + } + } + None } -/// Inspired by https://github.com/nickdeis/eslint-plugin-no-secrets/blob/master/utils.js#L93 -/// Adapted from https://docs.rs/entropy/latest/src/entropy/lib.rs.html#14-33 -/// Calculates Shannon entropy to measure the randomness of data. High entropy values indicate potentially -/// secret or sensitive information, as such data is typically more random and less predictable than regular text. -/// Useful for detecting API keys, passwords, and other secrets within code or configuration files. -fn calculate_shannon_entropy(data: &str) -> f64 { +/* +Uses Shannon Entropy as a base algorithm, then adds "boosts" for special patterns/occurrences. +For example, Continuous mixed cases (lIkE tHiS) are more likely to contribute to a higher score than single cases. +Symbols also contribute highly to secrets. + +TODO: This needs work. False positives/negatives are highlighted in valid.js and invalid.js. + +References: +- ChatGPT chat: https://chatgpt.com/share/670370bf-3e18-8011-8454-f3bd01be0319 +- Original paper for Shannon Entropy: https://ieeexplore.ieee.org/abstract/document/6773024/ +*/ +fn calculate_entropy_with_case_and_classes( + data: &str, + base_threshold: f64, + scaling_factor: f64, +) -> f64 { let mut freq = [0usize; 256]; let len = data.len(); + for &byte in data.as_bytes() { freq[byte as usize] += 1; } - let mut entropy = 0.0; + let mut shannon_entropy = 0.0; + let mut letter_count = 0; + let mut uppercase_count = 0; + let mut lowercase_count = 0; + let mut digit_count = 0; + let mut symbol_count = 0; + let mut case_switches = 0; + let mut previous_char_was_upper = false; + for count in freq.iter() { if *count > 0 { let p = *count as f64 / len as f64; - entropy -= p * p.log2(); + shannon_entropy -= p * p.log2(); } } - entropy + // Letter classification and case switching + for (i, c) in data.chars().enumerate() { + if c.is_ascii_alphabetic() { + letter_count += 1; + if c.is_uppercase() { + uppercase_count += 1; + if i > 0 && !previous_char_was_upper { + case_switches += 1; + } + previous_char_was_upper = true; + } else { + lowercase_count += 1; + if i > 0 && previous_char_was_upper { + case_switches += 1; + } + previous_char_was_upper = false; + } + } else if c.is_ascii_digit() { + digit_count += 1; + } else if !c.is_whitespace() { + symbol_count += 1; + } + } + + // Adjust entropy: case switches and symbol boosts + let case_entropy_boost = if uppercase_count > 0 && lowercase_count > 0 { + (case_switches as f64 / letter_count as f64) * 2.0 + } else { + 0.0 + }; + + let symbol_entropy_boost = if symbol_count > 0 { + symbol_count as f64 / len as f64 + } else { + 0.0 + }; + + let digit_entropy_boost = if digit_count > 0 { + digit_count as f64 / len as f64 + } else { + 0.0 + }; + + let adjusted_entropy = shannon_entropy + + (case_entropy_boost * 2.5) + + (symbol_entropy_boost * 1.5) + + digit_entropy_boost; + + // Apply exponential scaling to avoid excessive boosting for long, structured tokens + apply_exponential_entropy_scaling(adjusted_entropy, len, base_threshold, scaling_factor) +} + +/* + A simple mechanism to scale entropy as the string length increases, the reason being that + large length strings are likely to be secrets. + TODO: However, at some point there should definitely be a cutoff i.e. 100 characters, because it's + probably base64 data or something similar at that point. + This was taken from GPT, and I sadly couldn't find references for it. +*/ +fn apply_exponential_entropy_scaling( + entropy: f64, + token_length: usize, + base_threshold: f64, + scaling_factor: f64, +) -> f64 { + // We will apply a logarithmic dampening to prevent excessive scaling for long tokens + let scaling_adjustment = (token_length as f64 / scaling_factor).ln(); + base_threshold + entropy * scaling_adjustment } #[cfg(test)] diff --git a/crates/biome_js_analyze/tests/specs/nursery/noSecrets/invalid.js b/crates/biome_js_analyze/tests/specs/nursery/noSecrets/invalid.js index f9a465f17bcf..c64c6425d3a7 100644 --- a/crates/biome_js_analyze/tests/specs/nursery/noSecrets/invalid.js +++ b/crates/biome_js_analyze/tests/specs/nursery/noSecrets/invalid.js @@ -1,13 +1,24 @@ -const awsApiKey = "AKIA1234567890EXAMPLE" +const JWT = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c" +const JWT_BASE64 = "ZXlKaGJHY2lPaUpJVXpJMU5pSXNJbXRwWkNJNkltRmtaVzUwYVdGc0lpd2laR1ZtYjNkellUWXpJaXdpYVdGMElqb3hPREF3T0RNeE9UZzFPVGs1TkN3aWZRPT0" const slackToken = "xoxb-not-a-real-token-this-will-not-work"; +const awsApiKey = "AKIA1234567890EXAMPLE" const rsaPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEA1234567890..." const facebookToken = "facebook_app_id_12345abcde67890fghij12345"; const twitterApiKey = "twitter_api_key_1234567890abcdefghijklmnopqrstuvwxyz"; const githubToken = "github_pat_1234567890abcdefghijklmnopqrstuvwxyz"; -const clientSecret = "abcdefghijklmnopqrstuvwxyz" -const herokuApiKey = "heroku_api_key_1234abcd-1234-1234-1234-1234abcd5678"; -const genericSecret = "secret_1234567890abcdefghijklmnopqrstuvwxyz"; -const genericApiKey = "api_key_1234567890abcdefghijklmnopqrstuvwxyz"; +const hexEncodedSecret = "4d79207365706f7261746f722068656c6c6f20776f726c6421"; +const base64Secret = "TXkgc2VjcmV0IGtleSBwYXNzd29yZA=="; const slackKey = "https://hooks.slack.com/services/T12345678/B12345678/abcdefghijklmnopqrstuvwx" const twilioApiKey = "SK1234567890abcdefghijklmnopqrstuv"; const dbUrl = "postgres://user:password123@example.com:5432/dbname"; +const A_SECRET = "ZWVTjPQSdhwRgl204Hc51YCsritMIzn8B=/p9UyeX7xu6KkAGqfm3FJ+oObLDNEva"; +const A_LOWERCASE_SECRET = "zwvtjpqsdhwrgl204hc51ycsritmizn8b=/p9uyex7xu6kkagqfm3fj+oobldneva"; +const A_BEARER_TOKEN = "AAAAAAAAAAAAAAAAAAAAAMLheAAAAAAA0%2BuSeid%2BULvsea4JtiGRiSDSJSI%3DEUifiRBkKG5E2XzMDjRfl76ZC9Ub0wnz4XsNiRVBChTYbJcE3F"; +const VAULT = { + token: "AAAAAAAAAAAAAAAAAAAAAMLheAAAAAAA0%2BuSeid%2BULvsea4JtiGRiSDSJSI%3DEUifiRBkKG5E2XzMDjRfl76ZC9Ub0wnz4XsNiRVBChTYbJcE3F" +}; + +// TODO: Get these to work, they seem common and important +// const herokuApiKey = "abcd1234-5678-90ef-ghij-klmnopqrstuv"; +// const BASIC_AUTH_HEADER = "Authorization: Basic QWxhZGRpbjpPcGVuU2VzYW1l"; +// const password = "ZWVTjPQSdhwRgl204Hc51YCsritMIzn8B=/p9UyeX7xu6KkAGqfm3FJ+oObLDNEva"; diff --git a/crates/biome_js_analyze/tests/specs/nursery/noSecrets/invalid.js.snap b/crates/biome_js_analyze/tests/specs/nursery/noSecrets/invalid.js.snap index fde82b9501ff..8ddf29a626ce 100644 --- a/crates/biome_js_analyze/tests/specs/nursery/noSecrets/invalid.js.snap +++ b/crates/biome_js_analyze/tests/specs/nursery/noSecrets/invalid.js.snap @@ -4,39 +4,51 @@ expression: invalid.js --- # Input ```jsx -const awsApiKey = "AKIA1234567890EXAMPLE" +const JWT = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c" +const JWT_BASE64 = "ZXlKaGJHY2lPaUpJVXpJMU5pSXNJbXRwWkNJNkltRmtaVzUwYVdGc0lpd2laR1ZtYjNkellUWXpJaXdpYVdGMElqb3hPREF3T0RNeE9UZzFPVGs1TkN3aWZRPT0" const slackToken = "xoxb-not-a-real-token-this-will-not-work"; +const awsApiKey = "AKIA1234567890EXAMPLE" const rsaPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEA1234567890..." const facebookToken = "facebook_app_id_12345abcde67890fghij12345"; const twitterApiKey = "twitter_api_key_1234567890abcdefghijklmnopqrstuvwxyz"; const githubToken = "github_pat_1234567890abcdefghijklmnopqrstuvwxyz"; -const clientSecret = "abcdefghijklmnopqrstuvwxyz" -const herokuApiKey = "heroku_api_key_1234abcd-1234-1234-1234-1234abcd5678"; -const genericSecret = "secret_1234567890abcdefghijklmnopqrstuvwxyz"; -const genericApiKey = "api_key_1234567890abcdefghijklmnopqrstuvwxyz"; +const hexEncodedSecret = "4d79207365706f7261746f722068656c6c6f20776f726c6421"; +const base64Secret = "TXkgc2VjcmV0IGtleSBwYXNzd29yZA=="; const slackKey = "https://hooks.slack.com/services/T12345678/B12345678/abcdefghijklmnopqrstuvwx" const twilioApiKey = "SK1234567890abcdefghijklmnopqrstuv"; const dbUrl = "postgres://user:password123@example.com:5432/dbname"; +const A_SECRET = "ZWVTjPQSdhwRgl204Hc51YCsritMIzn8B=/p9UyeX7xu6KkAGqfm3FJ+oObLDNEva"; +const A_LOWERCASE_SECRET = "zwvtjpqsdhwrgl204hc51ycsritmizn8b=/p9uyex7xu6kkagqfm3fj+oobldneva"; +const A_BEARER_TOKEN = "AAAAAAAAAAAAAAAAAAAAAMLheAAAAAAA0%2BuSeid%2BULvsea4JtiGRiSDSJSI%3DEUifiRBkKG5E2XzMDjRfl76ZC9Ub0wnz4XsNiRVBChTYbJcE3F"; +const VAULT = { + token: "AAAAAAAAAAAAAAAAAAAAAMLheAAAAAAA0%2BuSeid%2BULvsea4JtiGRiSDSJSI%3DEUifiRBkKG5E2XzMDjRfl76ZC9Ub0wnz4XsNiRVBChTYbJcE3F" +}; + +// TODO: Get these to work, they seem common and important +// const herokuApiKey = "abcd1234-5678-90ef-ghij-klmnopqrstuv"; +// const BASIC_AUTH_HEADER = "Authorization: Basic QWxhZGRpbjpPcGVuU2VzYW1l"; +// const password = "ZWVTjPQSdhwRgl204Hc51YCsritMIzn8B=/p9UyeX7xu6KkAGqfm3FJ+oObLDNEva"; ``` # Diagnostics ``` -invalid.js:1:19 lint/nursery/noSecrets ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:1:13 lint/nursery/noSecrets ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Potential secret found. - > 1 │ const awsApiKey = "AKIA1234567890EXAMPLE" - │ ^^^^^^^^^^^^^^^^^^^^^^^ - 2 │ const slackToken = "xoxb-not-a-real-token-this-will-not-work"; - 3 │ const rsaPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEA1234567890..." + > 1 │ const JWT = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c" + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 2 │ const JWT_BASE64 = "ZXlKaGJHY2lPaUpJVXpJMU5pSXNJbXRwWkNJNkltRmtaVzUwYVdGc0lpd2laR1ZtYjNkellUWXpJaXdpYVdGMElqb3hPREF3T0RNeE9UZzFPVGs1TkN3aWZRPT0" + 3 │ const slackToken = "xoxb-not-a-real-token-this-will-not-work"; - i Type of secret detected: AWS API Key + i Type of secret detected: JSON Web Token (JWT) i Storing secrets in source code is a security risk. Consider the following steps: 1. Remove the secret from your code. If you've already committed it, consider removing the commit entirely from your git tree. 2. If needed, use environment variables or a secure secret management system to store sensitive data. - 3. If this is a false positive, consider adding an inline disable comment. + 3. If this is a false positive, consider adding an inline disable comment, or tweak the entropy threshold. See options in our docs. + This rule only catches basic vulnerabilities. For more robust, proper solutions, check out our recommendations at: https://biomejs.dev/linter/rules/no-secrets/#recommendations ``` @@ -46,172 +58,203 @@ invalid.js:2:20 lint/nursery/noSecrets ━━━━━━━━━━━━━ ! Potential secret found. - 1 │ const awsApiKey = "AKIA1234567890EXAMPLE" - > 2 │ const slackToken = "xoxb-not-a-real-token-this-will-not-work"; + 1 │ const JWT = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c" + > 2 │ const JWT_BASE64 = "ZXlKaGJHY2lPaUpJVXpJMU5pSXNJbXRwWkNJNkltRmtaVzUwYVdGc0lpd2laR1ZtYjNkellUWXpJaXdpYVdGMElqb3hPREF3T0RNeE9UZzFPVGs1TkN3aWZRPT0" + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 3 │ const slackToken = "xoxb-not-a-real-token-this-will-not-work"; + 4 │ const awsApiKey = "AKIA1234567890EXAMPLE" + + i Type of secret detected: Base64-encoded JWT + + i Storing secrets in source code is a security risk. Consider the following steps: + 1. Remove the secret from your code. If you've already committed it, consider removing the commit entirely from your git tree. + 2. If needed, use environment variables or a secure secret management system to store sensitive data. + 3. If this is a false positive, consider adding an inline disable comment, or tweak the entropy threshold. See options in our docs. + This rule only catches basic vulnerabilities. For more robust, proper solutions, check out our recommendations at: https://biomejs.dev/linter/rules/no-secrets/#recommendations + + +``` + +``` +invalid.js:3:20 lint/nursery/noSecrets ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Potential secret found. + + 1 │ const JWT = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c" + 2 │ const JWT_BASE64 = "ZXlKaGJHY2lPaUpJVXpJMU5pSXNJbXRwWkNJNkltRmtaVzUwYVdGc0lpd2laR1ZtYjNkellUWXpJaXdpYVdGMElqb3hPREF3T0RNeE9UZzFPVGs1TkN3aWZRPT0" + > 3 │ const slackToken = "xoxb-not-a-real-token-this-will-not-work"; │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - 3 │ const rsaPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEA1234567890..." - 4 │ const facebookToken = "facebook_app_id_12345abcde67890fghij12345"; + 4 │ const awsApiKey = "AKIA1234567890EXAMPLE" + 5 │ const rsaPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEA1234567890..." i Type of secret detected: Slack Token i Storing secrets in source code is a security risk. Consider the following steps: 1. Remove the secret from your code. If you've already committed it, consider removing the commit entirely from your git tree. 2. If needed, use environment variables or a secure secret management system to store sensitive data. - 3. If this is a false positive, consider adding an inline disable comment. + 3. If this is a false positive, consider adding an inline disable comment, or tweak the entropy threshold. See options in our docs. + This rule only catches basic vulnerabilities. For more robust, proper solutions, check out our recommendations at: https://biomejs.dev/linter/rules/no-secrets/#recommendations ``` ``` -invalid.js:3:23 lint/nursery/noSecrets ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:4:19 lint/nursery/noSecrets ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Potential secret found. - 1 │ const awsApiKey = "AKIA1234567890EXAMPLE" - 2 │ const slackToken = "xoxb-not-a-real-token-this-will-not-work"; - > 3 │ const rsaPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEA1234567890..." - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - 4 │ const facebookToken = "facebook_app_id_12345abcde67890fghij12345"; - 5 │ const twitterApiKey = "twitter_api_key_1234567890abcdefghijklmnopqrstuvwxyz"; + 2 │ const JWT_BASE64 = "ZXlKaGJHY2lPaUpJVXpJMU5pSXNJbXRwWkNJNkltRmtaVzUwYVdGc0lpd2laR1ZtYjNkellUWXpJaXdpYVdGMElqb3hPREF3T0RNeE9UZzFPVGs1TkN3aWZRPT0" + 3 │ const slackToken = "xoxb-not-a-real-token-this-will-not-work"; + > 4 │ const awsApiKey = "AKIA1234567890EXAMPLE" + │ ^^^^^^^^^^^^^^^^^^^^^^^ + 5 │ const rsaPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEA1234567890..." + 6 │ const facebookToken = "facebook_app_id_12345abcde67890fghij12345"; - i Type of secret detected: RSA Private Key + i Type of secret detected: AWS API Key i Storing secrets in source code is a security risk. Consider the following steps: 1. Remove the secret from your code. If you've already committed it, consider removing the commit entirely from your git tree. 2. If needed, use environment variables or a secure secret management system to store sensitive data. - 3. If this is a false positive, consider adding an inline disable comment. + 3. If this is a false positive, consider adding an inline disable comment, or tweak the entropy threshold. See options in our docs. + This rule only catches basic vulnerabilities. For more robust, proper solutions, check out our recommendations at: https://biomejs.dev/linter/rules/no-secrets/#recommendations ``` ``` -invalid.js:4:23 lint/nursery/noSecrets ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:5:23 lint/nursery/noSecrets ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Potential secret found. - 2 │ const slackToken = "xoxb-not-a-real-token-this-will-not-work"; - 3 │ const rsaPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEA1234567890..." - > 4 │ const facebookToken = "facebook_app_id_12345abcde67890fghij12345"; - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - 5 │ const twitterApiKey = "twitter_api_key_1234567890abcdefghijklmnopqrstuvwxyz"; - 6 │ const githubToken = "github_pat_1234567890abcdefghijklmnopqrstuvwxyz"; + 3 │ const slackToken = "xoxb-not-a-real-token-this-will-not-work"; + 4 │ const awsApiKey = "AKIA1234567890EXAMPLE" + > 5 │ const rsaPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEA1234567890..." + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 6 │ const facebookToken = "facebook_app_id_12345abcde67890fghij12345"; + 7 │ const twitterApiKey = "twitter_api_key_1234567890abcdefghijklmnopqrstuvwxyz"; - i Type of secret detected: Facebook OAuth + i Type of secret detected: RSA Private Key i Storing secrets in source code is a security risk. Consider the following steps: 1. Remove the secret from your code. If you've already committed it, consider removing the commit entirely from your git tree. 2. If needed, use environment variables or a secure secret management system to store sensitive data. - 3. If this is a false positive, consider adding an inline disable comment. + 3. If this is a false positive, consider adding an inline disable comment, or tweak the entropy threshold. See options in our docs. + This rule only catches basic vulnerabilities. For more robust, proper solutions, check out our recommendations at: https://biomejs.dev/linter/rules/no-secrets/#recommendations ``` ``` -invalid.js:5:23 lint/nursery/noSecrets ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:6:23 lint/nursery/noSecrets ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Potential secret found. - 3 │ const rsaPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEA1234567890..." - 4 │ const facebookToken = "facebook_app_id_12345abcde67890fghij12345"; - > 5 │ const twitterApiKey = "twitter_api_key_1234567890abcdefghijklmnopqrstuvwxyz"; - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - 6 │ const githubToken = "github_pat_1234567890abcdefghijklmnopqrstuvwxyz"; - 7 │ const clientSecret = "abcdefghijklmnopqrstuvwxyz" + 4 │ const awsApiKey = "AKIA1234567890EXAMPLE" + 5 │ const rsaPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEA1234567890..." + > 6 │ const facebookToken = "facebook_app_id_12345abcde67890fghij12345"; + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 7 │ const twitterApiKey = "twitter_api_key_1234567890abcdefghijklmnopqrstuvwxyz"; + 8 │ const githubToken = "github_pat_1234567890abcdefghijklmnopqrstuvwxyz"; - i Type of secret detected: Twitter OAuth + i Type of secret detected: Facebook OAuth i Storing secrets in source code is a security risk. Consider the following steps: 1. Remove the secret from your code. If you've already committed it, consider removing the commit entirely from your git tree. 2. If needed, use environment variables or a secure secret management system to store sensitive data. - 3. If this is a false positive, consider adding an inline disable comment. + 3. If this is a false positive, consider adding an inline disable comment, or tweak the entropy threshold. See options in our docs. + This rule only catches basic vulnerabilities. For more robust, proper solutions, check out our recommendations at: https://biomejs.dev/linter/rules/no-secrets/#recommendations ``` ``` -invalid.js:6:21 lint/nursery/noSecrets ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:7:23 lint/nursery/noSecrets ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Potential secret found. - 4 │ const facebookToken = "facebook_app_id_12345abcde67890fghij12345"; - 5 │ const twitterApiKey = "twitter_api_key_1234567890abcdefghijklmnopqrstuvwxyz"; - > 6 │ const githubToken = "github_pat_1234567890abcdefghijklmnopqrstuvwxyz"; - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - 7 │ const clientSecret = "abcdefghijklmnopqrstuvwxyz" - 8 │ const herokuApiKey = "heroku_api_key_1234abcd-1234-1234-1234-1234abcd5678"; + 5 │ const rsaPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEA1234567890..." + 6 │ const facebookToken = "facebook_app_id_12345abcde67890fghij12345"; + > 7 │ const twitterApiKey = "twitter_api_key_1234567890abcdefghijklmnopqrstuvwxyz"; + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 8 │ const githubToken = "github_pat_1234567890abcdefghijklmnopqrstuvwxyz"; + 9 │ const hexEncodedSecret = "4d79207365706f7261746f722068656c6c6f20776f726c6421"; - i Type of secret detected: GitHub + i Type of secret detected: Twitter OAuth i Storing secrets in source code is a security risk. Consider the following steps: 1. Remove the secret from your code. If you've already committed it, consider removing the commit entirely from your git tree. 2. If needed, use environment variables or a secure secret management system to store sensitive data. - 3. If this is a false positive, consider adding an inline disable comment. + 3. If this is a false positive, consider adding an inline disable comment, or tweak the entropy threshold. See options in our docs. + This rule only catches basic vulnerabilities. For more robust, proper solutions, check out our recommendations at: https://biomejs.dev/linter/rules/no-secrets/#recommendations ``` ``` -invalid.js:7:22 lint/nursery/noSecrets ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:8:21 lint/nursery/noSecrets ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Potential secret found. - 5 │ const twitterApiKey = "twitter_api_key_1234567890abcdefghijklmnopqrstuvwxyz"; - 6 │ const githubToken = "github_pat_1234567890abcdefghijklmnopqrstuvwxyz"; - > 7 │ const clientSecret = "abcdefghijklmnopqrstuvwxyz" - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - 8 │ const herokuApiKey = "heroku_api_key_1234abcd-1234-1234-1234-1234abcd5678"; - 9 │ const genericSecret = "secret_1234567890abcdefghijklmnopqrstuvwxyz"; + 6 │ const facebookToken = "facebook_app_id_12345abcde67890fghij12345"; + 7 │ const twitterApiKey = "twitter_api_key_1234567890abcdefghijklmnopqrstuvwxyz"; + > 8 │ const githubToken = "github_pat_1234567890abcdefghijklmnopqrstuvwxyz"; + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 9 │ const hexEncodedSecret = "4d79207365706f7261746f722068656c6c6f20776f726c6421"; + 10 │ const base64Secret = "TXkgc2VjcmV0IGtleSBwYXNzd29yZA=="; - i Type of secret detected: The string has a high entropy value + i Type of secret detected: GitHub i Storing secrets in source code is a security risk. Consider the following steps: 1. Remove the secret from your code. If you've already committed it, consider removing the commit entirely from your git tree. 2. If needed, use environment variables or a secure secret management system to store sensitive data. - 3. If this is a false positive, consider adding an inline disable comment. + 3. If this is a false positive, consider adding an inline disable comment, or tweak the entropy threshold. See options in our docs. + This rule only catches basic vulnerabilities. For more robust, proper solutions, check out our recommendations at: https://biomejs.dev/linter/rules/no-secrets/#recommendations ``` ``` -invalid.js:9:23 lint/nursery/noSecrets ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:9:26 lint/nursery/noSecrets ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Potential secret found. - 7 │ const clientSecret = "abcdefghijklmnopqrstuvwxyz" - 8 │ const herokuApiKey = "heroku_api_key_1234abcd-1234-1234-1234-1234abcd5678"; - > 9 │ const genericSecret = "secret_1234567890abcdefghijklmnopqrstuvwxyz"; - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - 10 │ const genericApiKey = "api_key_1234567890abcdefghijklmnopqrstuvwxyz"; + 7 │ const twitterApiKey = "twitter_api_key_1234567890abcdefghijklmnopqrstuvwxyz"; + 8 │ const githubToken = "github_pat_1234567890abcdefghijklmnopqrstuvwxyz"; + > 9 │ const hexEncodedSecret = "4d79207365706f7261746f722068656c6c6f20776f726c6421"; + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 10 │ const base64Secret = "TXkgc2VjcmV0IGtleSBwYXNzd29yZA=="; 11 │ const slackKey = "https://hooks.slack.com/services/T12345678/B12345678/abcdefghijklmnopqrstuvwx" - i Type of secret detected: The string has a high entropy value + i Type of secret detected: Detected high entropy string i Storing secrets in source code is a security risk. Consider the following steps: 1. Remove the secret from your code. If you've already committed it, consider removing the commit entirely from your git tree. 2. If needed, use environment variables or a secure secret management system to store sensitive data. - 3. If this is a false positive, consider adding an inline disable comment. + 3. If this is a false positive, consider adding an inline disable comment, or tweak the entropy threshold. See options in our docs. + This rule only catches basic vulnerabilities. For more robust, proper solutions, check out our recommendations at: https://biomejs.dev/linter/rules/no-secrets/#recommendations ``` ``` -invalid.js:10:23 lint/nursery/noSecrets ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +invalid.js:10:22 lint/nursery/noSecrets ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ! Potential secret found. - 8 │ const herokuApiKey = "heroku_api_key_1234abcd-1234-1234-1234-1234abcd5678"; - 9 │ const genericSecret = "secret_1234567890abcdefghijklmnopqrstuvwxyz"; - > 10 │ const genericApiKey = "api_key_1234567890abcdefghijklmnopqrstuvwxyz"; - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 8 │ const githubToken = "github_pat_1234567890abcdefghijklmnopqrstuvwxyz"; + 9 │ const hexEncodedSecret = "4d79207365706f7261746f722068656c6c6f20776f726c6421"; + > 10 │ const base64Secret = "TXkgc2VjcmV0IGtleSBwYXNzd29yZA=="; + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 11 │ const slackKey = "https://hooks.slack.com/services/T12345678/B12345678/abcdefghijklmnopqrstuvwx" 12 │ const twilioApiKey = "SK1234567890abcdefghijklmnopqrstuv"; - i Type of secret detected: The string has a high entropy value + i Type of secret detected: Detected high entropy string i Storing secrets in source code is a security risk. Consider the following steps: 1. Remove the secret from your code. If you've already committed it, consider removing the commit entirely from your git tree. 2. If needed, use environment variables or a secure secret management system to store sensitive data. - 3. If this is a false positive, consider adding an inline disable comment. + 3. If this is a false positive, consider adding an inline disable comment, or tweak the entropy threshold. See options in our docs. + This rule only catches basic vulnerabilities. For more robust, proper solutions, check out our recommendations at: https://biomejs.dev/linter/rules/no-secrets/#recommendations ``` @@ -221,8 +264,8 @@ invalid.js:11:18 lint/nursery/noSecrets ━━━━━━━━━━━━━ ! Potential secret found. - 9 │ const genericSecret = "secret_1234567890abcdefghijklmnopqrstuvwxyz"; - 10 │ const genericApiKey = "api_key_1234567890abcdefghijklmnopqrstuvwxyz"; + 9 │ const hexEncodedSecret = "4d79207365706f7261746f722068656c6c6f20776f726c6421"; + 10 │ const base64Secret = "TXkgc2VjcmV0IGtleSBwYXNzd29yZA=="; > 11 │ const slackKey = "https://hooks.slack.com/services/T12345678/B12345678/abcdefghijklmnopqrstuvwx" │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 12 │ const twilioApiKey = "SK1234567890abcdefghijklmnopqrstuv"; @@ -233,7 +276,8 @@ invalid.js:11:18 lint/nursery/noSecrets ━━━━━━━━━━━━━ i Storing secrets in source code is a security risk. Consider the following steps: 1. Remove the secret from your code. If you've already committed it, consider removing the commit entirely from your git tree. 2. If needed, use environment variables or a secure secret management system to store sensitive data. - 3. If this is a false positive, consider adding an inline disable comment. + 3. If this is a false positive, consider adding an inline disable comment, or tweak the entropy threshold. See options in our docs. + This rule only catches basic vulnerabilities. For more robust, proper solutions, check out our recommendations at: https://biomejs.dev/linter/rules/no-secrets/#recommendations ``` @@ -243,19 +287,20 @@ invalid.js:12:22 lint/nursery/noSecrets ━━━━━━━━━━━━━ ! Potential secret found. - 10 │ const genericApiKey = "api_key_1234567890abcdefghijklmnopqrstuvwxyz"; + 10 │ const base64Secret = "TXkgc2VjcmV0IGtleSBwYXNzd29yZA=="; 11 │ const slackKey = "https://hooks.slack.com/services/T12345678/B12345678/abcdefghijklmnopqrstuvwx" > 12 │ const twilioApiKey = "SK1234567890abcdefghijklmnopqrstuv"; │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 13 │ const dbUrl = "postgres://user:password123@example.com:5432/dbname"; - 14 │ + 14 │ const A_SECRET = "ZWVTjPQSdhwRgl204Hc51YCsritMIzn8B=/p9UyeX7xu6KkAGqfm3FJ+oObLDNEva"; i Type of secret detected: Twilio API Key i Storing secrets in source code is a security risk. Consider the following steps: 1. Remove the secret from your code. If you've already committed it, consider removing the commit entirely from your git tree. 2. If needed, use environment variables or a secure secret management system to store sensitive data. - 3. If this is a false positive, consider adding an inline disable comment. + 3. If this is a false positive, consider adding an inline disable comment, or tweak the entropy threshold. See options in our docs. + This rule only catches basic vulnerabilities. For more robust, proper solutions, check out our recommendations at: https://biomejs.dev/linter/rules/no-secrets/#recommendations ``` @@ -269,14 +314,108 @@ invalid.js:13:15 lint/nursery/noSecrets ━━━━━━━━━━━━━ 12 │ const twilioApiKey = "SK1234567890abcdefghijklmnopqrstuv"; > 13 │ const dbUrl = "postgres://user:password123@example.com:5432/dbname"; │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - 14 │ + 14 │ const A_SECRET = "ZWVTjPQSdhwRgl204Hc51YCsritMIzn8B=/p9UyeX7xu6KkAGqfm3FJ+oObLDNEva"; + 15 │ const A_LOWERCASE_SECRET = "zwvtjpqsdhwrgl204hc51ycsritmizn8b=/p9uyex7xu6kkagqfm3fj+oobldneva"; i Type of secret detected: Password in URL i Storing secrets in source code is a security risk. Consider the following steps: 1. Remove the secret from your code. If you've already committed it, consider removing the commit entirely from your git tree. 2. If needed, use environment variables or a secure secret management system to store sensitive data. - 3. If this is a false positive, consider adding an inline disable comment. + 3. If this is a false positive, consider adding an inline disable comment, or tweak the entropy threshold. See options in our docs. + This rule only catches basic vulnerabilities. For more robust, proper solutions, check out our recommendations at: https://biomejs.dev/linter/rules/no-secrets/#recommendations + + +``` + +``` +invalid.js:14:18 lint/nursery/noSecrets ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Potential secret found. + + 12 │ const twilioApiKey = "SK1234567890abcdefghijklmnopqrstuv"; + 13 │ const dbUrl = "postgres://user:password123@example.com:5432/dbname"; + > 14 │ const A_SECRET = "ZWVTjPQSdhwRgl204Hc51YCsritMIzn8B=/p9UyeX7xu6KkAGqfm3FJ+oObLDNEva"; + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 15 │ const A_LOWERCASE_SECRET = "zwvtjpqsdhwrgl204hc51ycsritmizn8b=/p9uyex7xu6kkagqfm3fj+oobldneva"; + 16 │ const A_BEARER_TOKEN = "AAAAAAAAAAAAAAAAAAAAAMLheAAAAAAA0%2BuSeid%2BULvsea4JtiGRiSDSJSI%3DEUifiRBkKG5E2XzMDjRfl76ZC9Ub0wnz4XsNiRVBChTYbJcE3F"; + + i Type of secret detected: Detected high entropy string + + i Storing secrets in source code is a security risk. Consider the following steps: + 1. Remove the secret from your code. If you've already committed it, consider removing the commit entirely from your git tree. + 2. If needed, use environment variables or a secure secret management system to store sensitive data. + 3. If this is a false positive, consider adding an inline disable comment, or tweak the entropy threshold. See options in our docs. + This rule only catches basic vulnerabilities. For more robust, proper solutions, check out our recommendations at: https://biomejs.dev/linter/rules/no-secrets/#recommendations + + +``` + +``` +invalid.js:15:28 lint/nursery/noSecrets ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Potential secret found. + + 13 │ const dbUrl = "postgres://user:password123@example.com:5432/dbname"; + 14 │ const A_SECRET = "ZWVTjPQSdhwRgl204Hc51YCsritMIzn8B=/p9UyeX7xu6KkAGqfm3FJ+oObLDNEva"; + > 15 │ const A_LOWERCASE_SECRET = "zwvtjpqsdhwrgl204hc51ycsritmizn8b=/p9uyex7xu6kkagqfm3fj+oobldneva"; + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 16 │ const A_BEARER_TOKEN = "AAAAAAAAAAAAAAAAAAAAAMLheAAAAAAA0%2BuSeid%2BULvsea4JtiGRiSDSJSI%3DEUifiRBkKG5E2XzMDjRfl76ZC9Ub0wnz4XsNiRVBChTYbJcE3F"; + 17 │ const VAULT = { + + i Type of secret detected: Detected high entropy string + + i Storing secrets in source code is a security risk. Consider the following steps: + 1. Remove the secret from your code. If you've already committed it, consider removing the commit entirely from your git tree. + 2. If needed, use environment variables or a secure secret management system to store sensitive data. + 3. If this is a false positive, consider adding an inline disable comment, or tweak the entropy threshold. See options in our docs. + This rule only catches basic vulnerabilities. For more robust, proper solutions, check out our recommendations at: https://biomejs.dev/linter/rules/no-secrets/#recommendations + + +``` + +``` +invalid.js:16:24 lint/nursery/noSecrets ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Potential secret found. + + 14 │ const A_SECRET = "ZWVTjPQSdhwRgl204Hc51YCsritMIzn8B=/p9UyeX7xu6KkAGqfm3FJ+oObLDNEva"; + 15 │ const A_LOWERCASE_SECRET = "zwvtjpqsdhwrgl204hc51ycsritmizn8b=/p9uyex7xu6kkagqfm3fj+oobldneva"; + > 16 │ const A_BEARER_TOKEN = "AAAAAAAAAAAAAAAAAAAAAMLheAAAAAAA0%2BuSeid%2BULvsea4JtiGRiSDSJSI%3DEUifiRBkKG5E2XzMDjRfl76ZC9Ub0wnz4XsNiRVBChTYbJcE3F"; + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 17 │ const VAULT = { + 18 │ token: "AAAAAAAAAAAAAAAAAAAAAMLheAAAAAAA0%2BuSeid%2BULvsea4JtiGRiSDSJSI%3DEUifiRBkKG5E2XzMDjRfl76ZC9Ub0wnz4XsNiRVBChTYbJcE3F" + + i Type of secret detected: Detected high entropy string + + i Storing secrets in source code is a security risk. Consider the following steps: + 1. Remove the secret from your code. If you've already committed it, consider removing the commit entirely from your git tree. + 2. If needed, use environment variables or a secure secret management system to store sensitive data. + 3. If this is a false positive, consider adding an inline disable comment, or tweak the entropy threshold. See options in our docs. + This rule only catches basic vulnerabilities. For more robust, proper solutions, check out our recommendations at: https://biomejs.dev/linter/rules/no-secrets/#recommendations + + +``` + +``` +invalid.js:18:10 lint/nursery/noSecrets ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Potential secret found. + + 16 │ const A_BEARER_TOKEN = "AAAAAAAAAAAAAAAAAAAAAMLheAAAAAAA0%2BuSeid%2BULvsea4JtiGRiSDSJSI%3DEUifiRBkKG5E2XzMDjRfl76ZC9Ub0wnz4XsNiRVBChTYbJcE3F"; + 17 │ const VAULT = { + > 18 │ token: "AAAAAAAAAAAAAAAAAAAAAMLheAAAAAAA0%2BuSeid%2BULvsea4JtiGRiSDSJSI%3DEUifiRBkKG5E2XzMDjRfl76ZC9Ub0wnz4XsNiRVBChTYbJcE3F" + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 19 │ }; + 20 │ + + i Type of secret detected: Detected high entropy string + + i Storing secrets in source code is a security risk. Consider the following steps: + 1. Remove the secret from your code. If you've already committed it, consider removing the commit entirely from your git tree. + 2. If needed, use environment variables or a secure secret management system to store sensitive data. + 3. If this is a false positive, consider adding an inline disable comment, or tweak the entropy threshold. See options in our docs. + This rule only catches basic vulnerabilities. For more robust, proper solutions, check out our recommendations at: https://biomejs.dev/linter/rules/no-secrets/#recommendations ``` diff --git a/crates/biome_js_analyze/tests/specs/nursery/noSecrets/valid.js b/crates/biome_js_analyze/tests/specs/nursery/noSecrets/valid.js index 0f4cb540dee8..81c61b9c1444 100644 --- a/crates/biome_js_analyze/tests/specs/nursery/noSecrets/valid.js +++ b/crates/biome_js_analyze/tests/specs/nursery/noSecrets/valid.js @@ -4,3 +4,39 @@ const count = 10; const nonSecret = "hello world" const nonSecretLong = "hello world, this is a looong string which I needed to create for some reason" const dbUrl = `postgres://user:${process.env.DB_PASSWORD}@example.com:5432/dbname`; +const NOT_A_SECRET = "I'm not a secret, I think"; +const NOT_A_SECRET_TEMPLATE = `A template that isn't a secret. ${1+1} = 2`; +const CSS_CLASSNAME = "hey-it-s-a-css-class-not-a-secret and-neither-this-one"; + +// From user tests +const codeCheck = "\nconst DEFAULT_CONFIG = /* @__PURE__ */ bare.Config({})\n"; +const otpCheck = 'Verify OTP Google Mobile Authenticator (2FAS)' +const bitcoinString = { + key: "0 USD,,. for {bitlocus|string}.", +}; +const textString = { + key: 'Verifying takes 15 approved the following 3.' +}; +const facebookAndAwsString = { + key: 'facebook.com |console.aws.amazon.com' +}; +const IsoString = { + key: 'ISO-27001 information , GDPR' +}; + +// Postgres json path query +const isNumeric = '@.scoreDisplayMode == "numeric" || @.scoreDisplayMode == "metricSavings"' +const tailwindClassNames = 'whitespace-nowrap bg-base-4 px-1 text-[0.65rem] group-hover:w-auto group-hover:overflow-visible' +const tailwindConfigOptions = { + theme: { + animation: { + slideDown: 'slideDown 300ms cubic-bezier(0.87, 0, 0.13, 1)', + } + } +} +export const url = 'https://www.nytimes.com/2024/03/05/arts/design/pritzker-prize-riken-yamamoto-architecture.html' + +// TODO: Remove these false positives, they unfortunately hurt the user experience. +// const NAMESPACE_CLASSNAME = 'Validation.JSONSchemaValidationUtilsImplFactory'; +// const BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; +// const webpackFriendlyConsole = require('./config/webpack/webpackFriendlyConsole'); \ No newline at end of file diff --git a/crates/biome_js_analyze/tests/specs/nursery/noSecrets/valid.js.snap b/crates/biome_js_analyze/tests/specs/nursery/noSecrets/valid.js.snap index 6a72ffebcdcd..a973ab6979aa 100644 --- a/crates/biome_js_analyze/tests/specs/nursery/noSecrets/valid.js.snap +++ b/crates/biome_js_analyze/tests/specs/nursery/noSecrets/valid.js.snap @@ -10,5 +10,40 @@ const count = 10; const nonSecret = "hello world" const nonSecretLong = "hello world, this is a looong string which I needed to create for some reason" const dbUrl = `postgres://user:${process.env.DB_PASSWORD}@example.com:5432/dbname`; +const NOT_A_SECRET = "I'm not a secret, I think"; +const NOT_A_SECRET_TEMPLATE = `A template that isn't a secret. ${1+1} = 2`; +const CSS_CLASSNAME = "hey-it-s-a-css-class-not-a-secret and-neither-this-one"; +// From user tests +const codeCheck = "\nconst DEFAULT_CONFIG = /* @__PURE__ */ bare.Config({})\n"; +const otpCheck = 'Verify OTP Google Mobile Authenticator (2FAS)' +const bitcoinString = { + key: "0 USD,,. for {bitlocus|string}.", +}; +const textString = { + key: 'Verifying takes 15 approved the following 3.' +}; +const facebookAndAwsString = { + key: 'facebook.com |console.aws.amazon.com' +}; +const IsoString = { + key: 'ISO-27001 information , GDPR' +}; + +// Postgres json path query +const isNumeric = '@.scoreDisplayMode == "numeric" || @.scoreDisplayMode == "metricSavings"' +const tailwindClassNames = 'whitespace-nowrap bg-base-4 px-1 text-[0.65rem] group-hover:w-auto group-hover:overflow-visible' +const tailwindConfigOptions = { + theme: { + animation: { + slideDown: 'slideDown 300ms cubic-bezier(0.87, 0, 0.13, 1)', + } + } +} +export const url = 'https://www.nytimes.com/2024/03/05/arts/design/pritzker-prize-riken-yamamoto-architecture.html' + +// TODO: Remove these false positives, they unfortunately hurt the user experience. +// const NAMESPACE_CLASSNAME = 'Validation.JSONSchemaValidationUtilsImplFactory'; +// const BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; +// const webpackFriendlyConsole = require('./config/webpack/webpackFriendlyConsole'); ``` diff --git a/packages/@biomejs/backend-jsonrpc/src/workspace.ts b/packages/@biomejs/backend-jsonrpc/src/workspace.ts index cec4521dfc32..f0d1456e802c 100644 --- a/packages/@biomejs/backend-jsonrpc/src/workspace.ts +++ b/packages/@biomejs/backend-jsonrpc/src/workspace.ts @@ -1289,7 +1289,7 @@ export interface Nursery { /** * Disallow usage of sensitive data such as API keys and tokens. */ - noSecrets?: RuleConfiguration_for_Null; + noSecrets?: RuleConfiguration_for_NoSecretsOptions; /** * Enforce that static, visible elements (such as \
) that have click handlers use the valid role attribute. */ @@ -2012,6 +2012,9 @@ export type RuleConfiguration_for_RestrictedImportsOptions = export type RuleFixConfiguration_for_NoRestrictedTypesOptions = | RulePlainConfiguration | RuleWithFixOptions_for_NoRestrictedTypesOptions; +export type RuleConfiguration_for_NoSecretsOptions = + | RulePlainConfiguration + | RuleWithOptions_for_NoSecretsOptions; export type RuleConfiguration_for_UseComponentExportOnlyModulesOptions = | RulePlainConfiguration | RuleWithOptions_for_UseComponentExportOnlyModulesOptions; @@ -2173,6 +2176,16 @@ export interface RuleWithFixOptions_for_NoRestrictedTypesOptions { */ options: NoRestrictedTypesOptions; } +export interface RuleWithOptions_for_NoSecretsOptions { + /** + * The severity of the emitted diagnostics by the rule + */ + level: RulePlainConfiguration; + /** + * Rule's options + */ + options: NoSecretsOptions; +} export interface RuleWithOptions_for_UseComponentExportOnlyModulesOptions { /** * The severity of the emitted diagnostics by the rule @@ -2369,6 +2382,12 @@ export interface RestrictedImportsOptions { export interface NoRestrictedTypesOptions { types?: {}; } +export interface NoSecretsOptions { + /** + * Set entropy threshold (default is 41). + */ + entropyThreshold?: number; +} export interface UseComponentExportOnlyModulesOptions { /** * Allows the export of constants. This option is for environments that support it, such as [Vite](https://vitejs.dev/) diff --git a/packages/@biomejs/biome/configuration_schema.json b/packages/@biomejs/biome/configuration_schema.json index c9f34aecfeee..7c49efd9e3c2 100644 --- a/packages/@biomejs/biome/configuration_schema.json +++ b/packages/@biomejs/biome/configuration_schema.json @@ -2059,6 +2059,24 @@ }, "additionalProperties": false }, + "NoSecretsConfiguration": { + "anyOf": [ + { "$ref": "#/definitions/RulePlainConfiguration" }, + { "$ref": "#/definitions/RuleWithNoSecretsOptions" } + ] + }, + "NoSecretsOptions": { + "type": "object", + "properties": { + "entropyThreshold": { + "description": "Set entropy threshold (default is 41).", + "type": ["integer", "null"], + "format": "uint16", + "minimum": 0.0 + } + }, + "additionalProperties": false + }, "Nursery": { "description": "A list of rules that belong to this group", "type": "object", @@ -2189,7 +2207,7 @@ "noSecrets": { "description": "Disallow usage of sensitive data such as API keys and tokens.", "anyOf": [ - { "$ref": "#/definitions/RuleConfiguration" }, + { "$ref": "#/definitions/NoSecretsConfiguration" }, { "type": "null" } ] }, @@ -2825,6 +2843,21 @@ }, "additionalProperties": false }, + "RuleWithNoSecretsOptions": { + "type": "object", + "required": ["level"], + "properties": { + "level": { + "description": "The severity of the emitted diagnostics by the rule", + "allOf": [{ "$ref": "#/definitions/RulePlainConfiguration" }] + }, + "options": { + "description": "Rule's options", + "allOf": [{ "$ref": "#/definitions/NoSecretsOptions" }] + } + }, + "additionalProperties": false + }, "RuleWithRestrictedGlobalsOptions": { "type": "object", "required": ["level"],