{
  "schema": "nacodex.secret_patterns",
  "schema_version": 1,
  "rules_version": "1.0.0",
  "guide_version": "1.0",
  "updated": "2026-10-05",
  "shared_by": [
    "AUDIT_PREP_GUIDE.md",
    "AI_PROMPT_AUDIT_PREP.md",
    "Nacodex on-device pre-upload scanner"
  ],
  "regex_dialect": "java.util.regex (Java 8+ / Kotlin). Only a leading inline flag group such as (?i) or (?im) is used. No possessive quantifiers, atomic groups, named groups or variable-length lookbehind. The JSON string is the regex after JSON unescaping.",
  "semantics": {
    "level": "A rule applies when its level is at or below the level the user chose. L0 always applies. L3 uses the same rules as L2; L3 extras (comments, string literals) are done by the user's AI and are not scanned.",
    "severity": "block = the app refuses to upload until the hit is fixed; the user cannot override. warn = the app shows the hit; the user may fix it or send anyway after confirming. Every L0 rule with severity warn is a heuristic with known false positives.",
    "kind": "filename = regex tested against the file's base name. path = regex tested against the archive-relative path using forward slashes. content = regex tested against the decoded text of the file.",
    "content_scan": "Run each content rule over the whole decoded text, not line by line (the 64-number array may span lines). Java flags: none beyond the inline group. Rules that need ^ and $ per line carry (?m).",
    "path_filter": "Optional. When present, a content rule only runs on files whose archive-relative path matches this regex.",
    "action": "exclude_file = drop the whole file from the copy. redact_value = replace the matched text (or capture group value_group when given) with placeholder. pseudonymize = replace with a consistent alias; keep the mapping local. review = a human or the AI decides.",
    "value_group": "Optional. Capture group number that holds only the value to replace. Absent means the whole match.",
    "placeholder": "Text to write in place of a redacted value. null when the whole file is dropped. Always inside the original quotes. In a typed context (an array of numbers) use a quoted string.",
    "never_log_values": true,
    "report_masking": "The app and the AI report file path, line number, rule id and the first 2 characters of the hit at most. Never the full value. Never write the value into NACODEX_PREP.json.",
    "encoding_note": "Case-insensitive rules use (?i). Java's \\d is ASCII by default; Python's is Unicode. Rules are written so both behave the same on ASCII input."
  },
  "scan": {
    "max_scan_bytes_per_file": 5242880,
    "chunk_overlap_bytes": 8192,
    "oversize_action": "Files larger than max_scan_bytes_per_file are scanned in chunks that overlap by chunk_overlap_bytes, up to max_total_scan_bytes_per_archive. A file that still cannot be fully scanned is reported as UNSCANNED (warn at L0, shown to the user, never silently skipped).",
    "max_total_scan_bytes_per_archive": 209715200,
    "max_files_per_archive": 20000,
    "max_hits_reported_per_file": 50,
    "decoding": "Strip a UTF-8 BOM. Decode UTF-16 when the file starts with FF FE or FE FF. Otherwise decode as UTF-8 and fall back to ISO-8859-1. Never fail on a decoding error.",
    "binary_sniff": {
      "bytes": 8192,
      "rule": "After BOM handling, a file whose first 8192 bytes contain a NUL byte is binary."
    },
    "binary_skip": {
      "skip_content_rules": true,
      "still_apply_rules": [
        "filename",
        "path"
      ],
      "extensions": [
        "png",
        "jpg",
        "jpeg",
        "gif",
        "webp",
        "bmp",
        "ico",
        "tif",
        "tiff",
        "heic",
        "mp3",
        "mp4",
        "m4a",
        "mov",
        "avi",
        "mkv",
        "wav",
        "ogg",
        "flac",
        "ttf",
        "otf",
        "woff",
        "woff2",
        "eot",
        "pdf",
        "so",
        "dll",
        "exe",
        "dylib",
        "a",
        "o",
        "lib",
        "class",
        "dex",
        "jar",
        "aar",
        "apk",
        "aab",
        "ipa",
        "wasm",
        "pyc",
        "bin"
      ],
      "note": "Images and PDFs are not scanned for text. They can still show private data (screenshots). At L1 and above the user is told to review or remove them; the app cannot check them."
    },
    "symlinks": "Never follow. A symlink in the archive is a block-level finding (SYMLINK_IN_ARCHIVE, raised by the app, not by a regex).",
    "archive_path_checks": "App-level, not regex: reject absolute paths, '..' segments, backslashes, duplicate entries and entries over the size caps."
  },
  "app_level_findings": [
    {
      "id": "SYMLINK_IN_ARCHIVE",
      "level": "L0",
      "severity": "block",
      "description": "ZIP entry is a symbolic link."
    },
    {
      "id": "UNSAFE_ARCHIVE_PATH",
      "level": "L0",
      "severity": "block",
      "description": "Absolute path, '..' segment or backslash in an entry name."
    },
    {
      "id": "MISSING_OR_BAD_MANIFEST",
      "level": "L0",
      "severity": "warn",
      "description": "NACODEX_PREP.json is missing, unreadable, or its level is lower than the level the user picked in the app."
    },
    {
      "id": "MANIFEST_CONTAINS_VALUE",
      "level": "L0",
      "severity": "block",
      "description": "A content rule matched inside NACODEX_PREP.json. The manifest must never hold values."
    },
    {
      "id": "UNSCANNED_FILE",
      "level": "L0",
      "severity": "warn",
      "description": "File too large or undecodable to scan fully."
    },
    {
      "id": "MAPPING_FILE_IN_ARCHIVE",
      "level": "L2",
      "severity": "block",
      "description": "A file named like the local alias map (*.mapping.local.json or NACODEX_ALIAS_MAP*) is inside the archive."
    }
  ],
  "rules": [
    {
      "id": "PRIVATE_KEY_FILE",
      "level": "L0",
      "severity": "block",
      "kind": "filename",
      "regex": "(?i)^(?:id_(?:rsa|dsa|ecdsa|ed25519)|[^/]*\\.(?:pem|key|pk8|p8|ppk|gpg|pgp|kdbx|keychain|keyring)|secring\\.[a-z]+)$",
      "description": "Private key or key-ring file. The audit never needs it. Public certificates (.crt, .cer) are fine.",
      "placeholder": null,
      "action": "exclude_file"
    },
    {
      "id": "KEYSTORE_FILE",
      "level": "L0",
      "severity": "block",
      "kind": "filename",
      "regex": "(?i)^[^/]*\\.(?:jks|keystore|bks|p12|pfx)$",
      "description": "Android or Java signing keystore, or PKCS12 bundle. Contains private signing keys.",
      "placeholder": null,
      "action": "exclude_file"
    },
    {
      "id": "SOLANA_KEYPAIR_FILE",
      "level": "L0",
      "severity": "block",
      "kind": "filename",
      "regex": "(?i)^(?:id\\.json|[^/]*keypair[^/]*\\.json)$",
      "description": "Solana CLI or Anchor keypair file (a JSON array of 64 numbers).",
      "placeholder": null,
      "action": "exclude_file"
    },
    {
      "id": "WALLET_FILE",
      "level": "L0",
      "severity": "block",
      "kind": "filename",
      "regex": "(?i)^(?:wallet\\.dat|[^/]*\\.wallet|UTC--[^/]+|[^/]*wallet[^/]*\\.keystore)$",
      "description": "Wallet file (Bitcoin wallet.dat, Ethereum UTC keystore, other .wallet exports).",
      "placeholder": null,
      "action": "exclude_file"
    },
    {
      "id": "WALLET_JSON_FILE",
      "level": "L0",
      "severity": "warn",
      "kind": "filename",
      "regex": "(?i)^[^/]*wallet[^/]*\\.json$",
      "description": "JSON file with 'wallet' in its name. May be a wallet export. If it holds only public addresses or UI strings, keep it.",
      "placeholder": null,
      "action": "review"
    },
    {
      "id": "SEED_NOTE_FILE",
      "level": "L0",
      "severity": "block",
      "kind": "filename",
      "regex": "(?i)^(?:seed(?:[_-]?phrase)?|mnemonic|recovery[_-]?phrase|secret[_-]?recovery)(?:[_. -][^/]*)?\\.(?:txt|md|json|rtf|csv)$",
      "description": "File named like a seed or recovery phrase note.",
      "placeholder": null,
      "action": "exclude_file"
    },
    {
      "id": "CREDENTIAL_FILE",
      "level": "L0",
      "severity": "block",
      "kind": "filename",
      "regex": "(?i)^(?:\\.netrc|_netrc|\\.git-credentials|\\.dockercfg|\\.htpasswd|\\.pgpass|\\.my\\.cnf|\\.s3cfg|credentials(?:\\.(?:json|ya?ml|ini|csv|txt|xml))?|service-?account[^/]*\\.json|serviceaccountkey[^/]*\\.json|client_secrets?[^/]*\\.json|secrets?\\.(?:ya?ml|json|toml|properties|ini|txt)|keystore\\.properties|signing\\.properties|[^/]*\\.secrets?)$",
      "description": "File that exists to hold credentials. Remove it from the copy.",
      "placeholder": null,
      "action": "exclude_file"
    },
    {
      "id": "CLOUD_CREDENTIAL_PATH",
      "level": "L0",
      "severity": "block",
      "kind": "path",
      "regex": "(?i)(?:^|/)(?:\\.aws/(?:credentials|config)|\\.kube/config|\\.docker/config\\.json|\\.ssh/[^/]+|\\.gnupg/[^/]+|\\.config/gcloud/[^/]+|\\.azure/[^/]+)$",
      "description": "Credential folders copied from a home directory (.aws, .kube, .ssh, .gnupg, gcloud, azure, docker).",
      "placeholder": null,
      "action": "exclude_file"
    },
    {
      "id": "IAC_STATE_FILE",
      "level": "L0",
      "severity": "block",
      "kind": "filename",
      "regex": "(?i)^(?:[^/]*\\.tfstate(?:\\.backup)?|[^/]*\\.tfvars)$",
      "description": "Terraform state or variable values. State files routinely contain secrets in clear text.",
      "placeholder": null,
      "action": "exclude_file"
    },
    {
      "id": "DB_FILE",
      "level": "L0",
      "severity": "block",
      "kind": "filename",
      "regex": "(?i)^[^/]*\\.(?:db|db3|sqlite|sqlite3|sqlitedb|sdb|mdb|accdb|mdf|ldf|realm|rdb|bson|dmp|dump|db-wal|db-shm|db-journal|sqlite-wal|sqlite-shm)$",
      "description": "Database file or dump. Holds user data. The audit reads schema and code, not rows.",
      "placeholder": null,
      "action": "exclude_file"
    },
    {
      "id": "DB_DUMP_FILE",
      "level": "L0",
      "severity": "block",
      "kind": "filename",
      "regex": "(?i)^(?:[^/]*[_.-])?(?:dump|backup)(?:[_.-][^/]*)?\\.sql(?:\\.(?:gz|bz2|xz|zip))?$",
      "description": "SQL dump or backup file. Schema and migration files are fine; data dumps are not.",
      "placeholder": null,
      "action": "exclude_file"
    },
    {
      "id": "COOKIE_SESSION_FILE",
      "level": "L0",
      "severity": "block",
      "kind": "filename",
      "regex": "(?i)^(?:cookies?(?:\\.(?:txt|sqlite|json|db))?|[^/]*\\.session|storage[_-]state\\.json|sessions?\\.(?:json|db|sqlite))$",
      "description": "Browser cookie jar or saved login session.",
      "placeholder": null,
      "action": "exclude_file"
    },
    {
      "id": "TRAFFIC_CAPTURE_FILE",
      "level": "L0",
      "severity": "block",
      "kind": "filename",
      "regex": "(?i)^[^/]*\\.(?:har|pcap|pcapng)$",
      "description": "Network capture. Contains tokens, cookies and request bodies.",
      "placeholder": null,
      "action": "exclude_file"
    },
    {
      "id": "SHELL_HISTORY_FILE",
      "level": "L0",
      "severity": "block",
      "kind": "filename",
      "regex": "(?i)^\\.(?:bash_history|zsh_history|python_history|node_repl_history|psql_history|mysql_history|sqlite_history|rediscli_history)$",
      "description": "Shell or REPL history. Often contains pasted secrets.",
      "placeholder": null,
      "action": "exclude_file"
    },
    {
      "id": "LOCAL_PROPERTIES_FILE",
      "level": "L0",
      "severity": "block",
      "kind": "filename",
      "regex": "^local\\.properties$",
      "description": "Android local.properties. Machine-local (SDK path with your user name) and often holds API keys and keystore passwords. Not source code.",
      "placeholder": null,
      "action": "exclude_file"
    },
    {
      "id": "NESTED_ARCHIVE_FILE",
      "level": "L0",
      "severity": "block",
      "kind": "filename",
      "regex": "(?i)^[^/]*\\.(?:zip|tar|tgz|gz|bz2|xz|7z|rar|tbz2|txz|zst)$",
      "description": "Archive inside the archive. It cannot be scanned, so it could hide anything. Unpack and prepare its files, or leave it out.",
      "placeholder": null,
      "action": "exclude_file"
    },
    {
      "id": "VCS_DIRECTORY",
      "level": "L0",
      "severity": "block",
      "kind": "path",
      "regex": "(?:^|/)\\.(?:git|hg|svn)(?:/|$)",
      "description": "Version-control folder. History can hold secrets that were deleted later, and packed objects cannot be scanned. Never send it.",
      "placeholder": null,
      "action": "exclude_file"
    },
    {
      "id": "PRIVATE_KEY_BLOCK",
      "level": "L0",
      "severity": "block",
      "kind": "content",
      "regex": "-----BEGIN (?:(?:RSA|EC|DSA|OPENSSH|ENCRYPTED|PGP) )?PRIVATE KEY(?: BLOCK)?-----",
      "description": "PEM, OpenSSH, PKCS8 or PGP private key block. Replace everything from the BEGIN line to the END line.",
      "placeholder": "<<REDACTED:PRIVATE_KEY>>",
      "action": "redact_value"
    },
    {
      "id": "SOLANA_SECRET_KEY_ARRAY",
      "level": "L0",
      "severity": "block",
      "kind": "content",
      "regex": "\\[\\s*(?:(?:25[0-5]|2[0-4]\\d|1?\\d?\\d)\\s*,\\s*){63}(?:25[0-5]|2[0-4]\\d|1?\\d?\\d)\\s*,?\\s*\\]",
      "description": "Array of exactly 64 byte values (0-255): a Solana keypair secret. Also matches when pretty-printed over many lines.",
      "placeholder": "<<REDACTED:SOLANA_SECRET_KEY>>",
      "action": "redact_value"
    },
    {
      "id": "SOLANA_SEED_BYTES_NEAR_KEYWORD",
      "level": "L0",
      "severity": "warn",
      "kind": "content",
      "regex": "(?i)(?:secret|seed|private|priv_?key)[^\\n]{0,40}?\\[\\s*(?:(?:25[0-5]|2[0-4]\\d|1?\\d?\\d)\\s*,\\s*){31}(?:25[0-5]|2[0-4]\\d|1?\\d?\\d)\\s*,?\\s*\\]",
      "description": "Array of 32 byte values next to the words secret, seed or private. May be an ed25519 seed. A bare 32-byte array is usually a public key, so this is a warning.",
      "placeholder": "<<REDACTED:SOLANA_SECRET_KEY>>",
      "action": "redact_value"
    },
    {
      "id": "BASE58_SECRET_NEAR_KEYWORD",
      "level": "L0",
      "severity": "block",
      "kind": "content",
      "regex": "(?i)(?:secret|private|priv_?key|keypair|seed)[A-Za-z0-9_\\-]{0,20}[\\\"'\\]\\s:=,(]{1,8}(?:[A-Za-z0-9_.]{1,30}\\(\\s*)?[\\\"']?(?<![1-9A-HJ-NP-Za-km-z])[1-9A-HJ-NP-Za-km-z]{87,88}(?![1-9A-HJ-NP-Za-km-z])",
      "description": "Base58 string of 87-88 characters (a 64-byte Solana secret key) right after a name containing secret, private, keypair or seed. Also catches Keypair.fromSecretKey(bs58.decode('...')).",
      "placeholder": "<<REDACTED:SOLANA_SECRET_KEY>>",
      "action": "redact_value"
    },
    {
      "id": "BASE58_BARE_LONG",
      "level": "L0",
      "severity": "warn",
      "kind": "content",
      "regex": "(?<![1-9A-HJ-NP-Za-km-z])[1-9A-HJ-NP-Za-km-z]{87,88}(?![1-9A-HJ-NP-Za-km-z])",
      "description": "Base58 string of 87-88 characters. Could be a secret key or a public transaction signature. Check it. If it is a signature, keep it.",
      "placeholder": "<<REDACTED:SOLANA_SECRET_KEY>>",
      "action": "review"
    },
    {
      "id": "HEX_PRIVATE_KEY_NEAR_KEYWORD",
      "level": "L0",
      "severity": "block",
      "kind": "content",
      "regex": "(?i)(?:private[_-]?key|priv[_-]?key|secret[_-]?key|signer[_-]?key|deployer[_-]?key)[^\\n]{0,30}?(?<![0-9a-fA-F])(?:0x)?[0-9a-fA-F]{64}(?![0-9a-fA-F])",
      "description": "64 hex characters next to a private-key name (EVM and other chains).",
      "placeholder": "<<REDACTED:PRIVATE_KEY>>",
      "action": "redact_value"
    },
    {
      "id": "MNEMONIC_ASSIGNED",
      "level": "L0",
      "severity": "block",
      "kind": "content",
      "regex": "(?i)(?:mnemonic|seed[ _-]?phrase|recovery[ _-]?phrase|secret[ _-]?recovery[ _-]?phrase|seed[ _-]?words)[\\\"']?\\s*[:=(]\\s*[\\\"'`]?(?:[a-z]{3,8} ){11}[a-z]{3,8}\\b",
      "description": "A 12 to 24 word phrase assigned to a name like mnemonic or seedPhrase.",
      "placeholder": "<<REDACTED:SEED_PHRASE>>",
      "action": "redact_value"
    },
    {
      "id": "SEED_PHRASE_BARE_LINE",
      "level": "L0",
      "severity": "warn",
      "kind": "content",
      "regex": "(?m)^[ \\t]*[\\\"'`]?(?:[a-z]{3,8} ){11}[a-z]{3,8}(?: [a-z]{3,8}){0,12}[\\\"'`]?[,;]?[ \\t]*\\r?$",
      "description": "A line made only of 12 to 24 short lowercase words. Heuristic and weak. Could be a seed phrase or ordinary text.",
      "placeholder": "<<REDACTED:SEED_PHRASE>>",
      "action": "review"
    },
    {
      "id": "AGE_SECRET_KEY",
      "level": "L0",
      "severity": "block",
      "kind": "content",
      "regex": "AGE-SECRET-KEY-1[A-Z0-9]{58}",
      "description": "age encryption secret key.",
      "placeholder": "<<REDACTED:PRIVATE_KEY>>",
      "action": "redact_value"
    },
    {
      "id": "AWS_ACCESS_KEY_ID",
      "level": "L0",
      "severity": "block",
      "kind": "content",
      "regex": "(?<![A-Za-z0-9])(?:AKIA|ASIA|AGPA|AIDA|AROA|ANPA)[0-9A-Z]{16}(?![A-Za-z0-9])",
      "description": "AWS access key ID.",
      "placeholder": "<<REDACTED:API_KEY>>",
      "action": "redact_value"
    },
    {
      "id": "AWS_SECRET_ACCESS_KEY",
      "level": "L0",
      "severity": "block",
      "kind": "content",
      "regex": "(?i)aws[_-]?secret[_-]?access[_-]?key[\\\"']?\\s*[:=]\\s*[\\\"']?[A-Za-z0-9/+=]{40}(?![A-Za-z0-9/+=])",
      "description": "AWS secret access key.",
      "placeholder": "<<REDACTED:API_KEY>>",
      "action": "redact_value"
    },
    {
      "id": "GOOGLE_API_KEY",
      "level": "L0",
      "severity": "block",
      "kind": "content",
      "regex": "(?<![A-Za-z0-9_\\-])AIza[0-9A-Za-z_\\-]{35}(?![A-Za-z0-9_\\-])",
      "description": "Google or Firebase API key. Often public by design, but an unrestricted key can be abused at your cost. The audit does not need the value.",
      "placeholder": "<<REDACTED:API_KEY>>",
      "action": "redact_value"
    },
    {
      "id": "GOOGLE_OAUTH_CLIENT_SECRET",
      "level": "L0",
      "severity": "block",
      "kind": "content",
      "regex": "GOCSPX-[A-Za-z0-9_\\-]{28}",
      "description": "Google OAuth client secret.",
      "placeholder": "<<REDACTED:API_KEY>>",
      "action": "redact_value"
    },
    {
      "id": "GCP_SERVICE_ACCOUNT_JSON",
      "level": "L0",
      "severity": "block",
      "kind": "content",
      "regex": "\\\"type\\\"\\s*:\\s*\\\"service_account\\\"",
      "description": "Google Cloud service-account key file. Leave the whole file out.",
      "placeholder": null,
      "action": "exclude_file"
    },
    {
      "id": "AZURE_STORAGE_ACCOUNT_KEY",
      "level": "L0",
      "severity": "block",
      "kind": "content",
      "regex": "(?i)AccountKey=[A-Za-z0-9+/]{40,}={0,2}",
      "description": "Azure storage connection-string key.",
      "placeholder": "<<REDACTED:API_KEY>>",
      "action": "redact_value"
    },
    {
      "id": "GITHUB_TOKEN",
      "level": "L0",
      "severity": "block",
      "kind": "content",
      "regex": "(?<![A-Za-z0-9_])(?:gh[pousr]_[A-Za-z0-9]{36,255}|github_pat_[A-Za-z0-9_]{50,255})(?![A-Za-z0-9_])",
      "description": "GitHub personal, OAuth, app or fine-grained token.",
      "placeholder": "<<REDACTED:TOKEN>>",
      "action": "redact_value"
    },
    {
      "id": "GITLAB_TOKEN",
      "level": "L0",
      "severity": "block",
      "kind": "content",
      "regex": "(?<![A-Za-z0-9_\\-])glpat-[A-Za-z0-9_\\-]{20,}",
      "description": "GitLab personal access token.",
      "placeholder": "<<REDACTED:TOKEN>>",
      "action": "redact_value"
    },
    {
      "id": "SLACK_TOKEN",
      "level": "L0",
      "severity": "block",
      "kind": "content",
      "regex": "(?<![A-Za-z0-9])xox[abprs]-[A-Za-z0-9\\-]{10,}",
      "description": "Slack token.",
      "placeholder": "<<REDACTED:TOKEN>>",
      "action": "redact_value"
    },
    {
      "id": "SLACK_WEBHOOK_URL",
      "level": "L0",
      "severity": "block",
      "kind": "content",
      "regex": "https://hooks\\.slack\\.com/services/T[A-Za-z0-9]+/B[A-Za-z0-9]+/[A-Za-z0-9]+",
      "description": "Slack incoming-webhook URL. Anyone with it can post to your channel.",
      "placeholder": "<<REDACTED:WEBHOOK_URL>>",
      "action": "redact_value"
    },
    {
      "id": "DISCORD_WEBHOOK_URL",
      "level": "L0",
      "severity": "block",
      "kind": "content",
      "regex": "https://(?:ptb\\.|canary\\.)?discord(?:app)?\\.com/api/webhooks/\\d+/[A-Za-z0-9_\\-]+",
      "description": "Discord webhook URL.",
      "placeholder": "<<REDACTED:WEBHOOK_URL>>",
      "action": "redact_value"
    },
    {
      "id": "STRIPE_LIVE_SECRET_KEY",
      "level": "L0",
      "severity": "block",
      "kind": "content",
      "regex": "(?<![A-Za-z0-9_])(?:sk|rk)_live_[0-9A-Za-z]{16,}",
      "description": "Stripe live secret or restricted key.",
      "placeholder": "<<REDACTED:API_KEY>>",
      "action": "redact_value"
    },
    {
      "id": "STRIPE_TEST_SECRET_KEY",
      "level": "L0",
      "severity": "warn",
      "kind": "content",
      "regex": "(?<![A-Za-z0-9_])(?:sk|rk)_test_[0-9A-Za-z]{16,}",
      "description": "Stripe test secret key. Not money, but still a credential. Replace it.",
      "placeholder": "<<REDACTED:API_KEY>>",
      "action": "redact_value"
    },
    {
      "id": "STRIPE_WEBHOOK_SECRET",
      "level": "L0",
      "severity": "block",
      "kind": "content",
      "regex": "(?<![A-Za-z0-9_])whsec_[A-Za-z0-9]{16,}",
      "description": "Stripe webhook signing secret.",
      "placeholder": "<<REDACTED:WEBHOOK_SECRET>>",
      "action": "redact_value"
    },
    {
      "id": "ANTHROPIC_API_KEY",
      "level": "L0",
      "severity": "block",
      "kind": "content",
      "regex": "sk-ant-[A-Za-z0-9_\\-]{20,}",
      "description": "Anthropic API key.",
      "placeholder": "<<REDACTED:API_KEY>>",
      "action": "redact_value"
    },
    {
      "id": "OPENAI_API_KEY",
      "level": "L0",
      "severity": "block",
      "kind": "content",
      "regex": "(?<![A-Za-z0-9_\\-])sk-(?!ant-)(?:proj-|svcacct-|admin-)?[A-Za-z0-9_\\-]{32,}",
      "description": "OpenAI-style secret key.",
      "placeholder": "<<REDACTED:API_KEY>>",
      "action": "redact_value"
    },
    {
      "id": "SENDGRID_API_KEY",
      "level": "L0",
      "severity": "block",
      "kind": "content",
      "regex": "(?<![A-Za-z0-9])SG\\.[A-Za-z0-9_\\-]{22}\\.[A-Za-z0-9_\\-]{43}",
      "description": "SendGrid API key.",
      "placeholder": "<<REDACTED:API_KEY>>",
      "action": "redact_value"
    },
    {
      "id": "TWILIO_API_KEY",
      "level": "L0",
      "severity": "block",
      "kind": "content",
      "regex": "(?<![A-Za-z0-9])SK[0-9a-f]{32}(?![A-Za-z0-9])",
      "description": "Twilio API key SID.",
      "placeholder": "<<REDACTED:API_KEY>>",
      "action": "redact_value"
    },
    {
      "id": "TELEGRAM_BOT_TOKEN",
      "level": "L0",
      "severity": "block",
      "kind": "content",
      "regex": "(?<![0-9])\\d{8,10}:AA[A-Za-z0-9_\\-]{33}(?![A-Za-z0-9_\\-])",
      "description": "Telegram bot token.",
      "placeholder": "<<REDACTED:TOKEN>>",
      "action": "redact_value"
    },
    {
      "id": "NPM_TOKEN",
      "level": "L0",
      "severity": "block",
      "kind": "content",
      "regex": "(?<![A-Za-z0-9_])npm_[A-Za-z0-9]{36}(?![A-Za-z0-9])",
      "description": "npm access token.",
      "placeholder": "<<REDACTED:TOKEN>>",
      "action": "redact_value"
    },
    {
      "id": "PYPI_TOKEN",
      "level": "L0",
      "severity": "block",
      "kind": "content",
      "regex": "pypi-AgEIcHlwaS5vcmc[A-Za-z0-9_\\-]{50,}",
      "description": "PyPI upload token.",
      "placeholder": "<<REDACTED:TOKEN>>",
      "action": "redact_value"
    },
    {
      "id": "HUGGINGFACE_TOKEN",
      "level": "L0",
      "severity": "block",
      "kind": "content",
      "regex": "(?<![A-Za-z0-9_])hf_[A-Za-z0-9]{34}(?![A-Za-z0-9])",
      "description": "Hugging Face token.",
      "placeholder": "<<REDACTED:TOKEN>>",
      "action": "redact_value"
    },
    {
      "id": "GROQ_API_KEY",
      "level": "L0",
      "severity": "block",
      "kind": "content",
      "regex": "(?<![A-Za-z0-9_])gsk_[A-Za-z0-9]{40,}",
      "description": "Groq API key.",
      "placeholder": "<<REDACTED:API_KEY>>",
      "action": "redact_value"
    },
    {
      "id": "DIGITALOCEAN_TOKEN",
      "level": "L0",
      "severity": "block",
      "kind": "content",
      "regex": "(?<![A-Za-z0-9_])do[opr]_v1_[a-f0-9]{64}",
      "description": "DigitalOcean token.",
      "placeholder": "<<REDACTED:TOKEN>>",
      "action": "redact_value"
    },
    {
      "id": "FCM_SERVER_KEY",
      "level": "L0",
      "severity": "block",
      "kind": "content",
      "regex": "AAAA[A-Za-z0-9_\\-]{7}:APA91b[A-Za-z0-9_\\-]{100,}",
      "description": "Firebase Cloud Messaging legacy server key.",
      "placeholder": "<<REDACTED:API_KEY>>",
      "action": "redact_value"
    },
    {
      "id": "RPC_PROVIDER_URL_WITH_KEY",
      "level": "L0",
      "severity": "block",
      "kind": "content",
      "regex": "(?i)https?://[a-z0-9.\\-]*(?:helius-rpc\\.com|helius\\.xyz|quiknode\\.pro|alchemy\\.com|infura\\.io|rpcpool\\.com|chainstacklabs\\.com)/[^\\s\\\"'<>]*?[A-Za-z0-9_\\-]{20,}",
      "description": "Blockchain RPC endpoint with the provider key in the URL or query string.",
      "placeholder": "<<REDACTED:API_KEY>>",
      "action": "redact_value"
    },
    {
      "id": "JWT_TOKEN",
      "level": "L0",
      "severity": "block",
      "kind": "content",
      "regex": "(?<![A-Za-z0-9_\\-])eyJ[A-Za-z0-9_\\-]{10,}\\.eyJ[A-Za-z0-9_\\-]{10,}\\.[A-Za-z0-9_\\-]{10,}",
      "description": "JSON Web Token (a bearer credential).",
      "placeholder": "<<REDACTED:JWT>>",
      "action": "redact_value"
    },
    {
      "id": "AUTH_HEADER_VALUE",
      "level": "L0",
      "severity": "block",
      "kind": "content",
      "regex": "(?i)authorization[\\\"']?\\s*[:=]\\s*[\\\"']?(?:bearer|basic|token)\\s+(?!<<REDACTED|your|<|\\$|\\{)[A-Za-z0-9._~+/\\-]{16,}=*",
      "description": "Authorization header with a literal credential.",
      "placeholder": "<<REDACTED:TOKEN>>",
      "action": "redact_value"
    },
    {
      "id": "BEARER_TOKEN_LITERAL",
      "level": "L0",
      "severity": "block",
      "kind": "content",
      "regex": "(?i)\\bbearer\\s+(?!<<REDACTED|your|<)[A-Za-z0-9._~+/\\-]{20,}=*",
      "description": "A literal bearer token (for example in a curl example or a test).",
      "placeholder": "<<REDACTED:TOKEN>>",
      "action": "redact_value"
    },
    {
      "id": "COOKIE_HEADER_VALUE",
      "level": "L0",
      "severity": "block",
      "kind": "content",
      "regex": "(?i)(?:set-)?cookie[\\\"']?\\s*[:=]\\s*[\\\"']?[A-Za-z0-9_\\-.]+=(?!<<REDACTED|\\$|\\{|<)[A-Za-z0-9%._~+/\\-]{16,}",
      "description": "Cookie header with a literal session value.",
      "placeholder": "<<REDACTED:COOKIE>>",
      "action": "redact_value"
    },
    {
      "id": "URL_EMBEDDED_PASSWORD",
      "level": "L0",
      "severity": "block",
      "kind": "content",
      "regex": "\\b((?:postgres(?:ql)?|mysql|mariadb|mongodb(?:\\+srv)?|redis|rediss|amqps?|https?|ftps?|sftp|ssh|smtps?)://[^\\s:/@\\\"'<>$]+:)([^\\s@/\\\"'<>$]{3,})(@[^\\s\\\"'<>]+)",
      "description": "Connection string or URL with user:password@host. Replace only the password part (group 2) and keep the rest.",
      "placeholder": "<<REDACTED:PASSWORD>>",
      "action": "redact_value",
      "value_group": 2
    },
    {
      "id": "KEYSTORE_PASSWORD_BUILD_SCRIPT",
      "level": "L0",
      "severity": "block",
      "kind": "content",
      "regex": "(?i)\\b(?:storePassword|keyPassword|keystorePassword|keyStorePass|storepass|keypass)\\b[\\\"']?\\s*[:=]?\\s*[\\\"'](?!<<REDACTED|\\$|\\{|<|%)[^\\\"'\\r\\n]{4,}[\\\"']",
      "description": "Android signing password written in a Gradle or similar build script.",
      "placeholder": "<<REDACTED:KEYSTORE_PASSWORD>>",
      "action": "redact_value"
    },
    {
      "id": "NPMRC_AUTH",
      "level": "L0",
      "severity": "block",
      "kind": "content",
      "regex": "(?i)(?:^|[\\s:/])_auth(?:token|password)?\\s*=\\s*(?!\\$|<<REDACTED)[^\\s]{6,}",
      "description": "npm registry auth line.",
      "placeholder": "<<REDACTED:TOKEN>>",
      "action": "redact_value"
    },
    {
      "id": "SQL_DUMP_HEADER",
      "level": "L0",
      "severity": "block",
      "kind": "content",
      "regex": "(?m)^--\\s*(?:PostgreSQL database dump|MySQL dump|Dumping data for table)",
      "description": "Header written by pg_dump or mysqldump. The file is a data dump. Leave it out.",
      "placeholder": null,
      "action": "exclude_file"
    },
    {
      "id": "GENERIC_SECRET_ASSIGNED_QUOTED",
      "level": "L0",
      "severity": "block",
      "kind": "content",
      "regex": "(?i)(?:secret|token|passw(?:or)?d|pwd|api[_-]?key|apikey|private[_-]?key|access[_-]?key|auth[_-]?key|credential)s?[\\\"']?(?:\\s*:\\s*[A-Za-z_][A-Za-z0-9_<>?.]*)?\\s*(?::=|=>|=|:)\\s*(?:[rbu])?[\\\"'`](?!(?:<<REDACTED|your|<|\\$|\\{|%|xxx|\\*|change[_-]?me|example|placeholder|dummy|none|null|todo|test|sample|redacted|undefined))(?=[^\\s\\\"'`<>$\\\\]*[0-9!@#%^&*+=/~?])[^\\s\\\"'`<>$\\\\]{8,}[\\\"'`]",
      "description": "A secret-like name (secret, token, password, api key, private key, credential) assigned a literal string of 8 or more characters that contains a digit or a symbol. Replace the string.",
      "placeholder": "<<REDACTED:CREDENTIAL>>",
      "action": "redact_value"
    },
    {
      "id": "GENERIC_SECRET_ASSIGNED_WORDLIKE",
      "level": "L0",
      "severity": "warn",
      "kind": "content",
      "regex": "(?i)(?:secret|token|passw(?:or)?d|pwd|api[_-]?key|apikey|private[_-]?key|access[_-]?key|auth[_-]?key|credential)s?[\\\"']?(?:\\s*:\\s*[A-Za-z_][A-Za-z0-9_<>?.]*)?\\s*(?::=|=>|=|:)\\s*(?:[rbu])?[\\\"'`](?!(?:<<REDACTED|your|<|\\$|\\{|%|xxx|\\*|change[_-]?me|example|placeholder|dummy|none|null|todo|test|sample|redacted|undefined))[A-Za-z][A-Za-z\\-]{11,}[\\\"'`]",
      "description": "A secret-like name assigned a long string of letters only. Could be a passphrase, or just a settings key such as KEY_TOKEN = \"access_token\". Check it.",
      "placeholder": "<<REDACTED:CREDENTIAL>>",
      "action": "review"
    },
    {
      "id": "GENERIC_SECRET_ASSIGNED_CONFIG",
      "level": "L0",
      "severity": "block",
      "kind": "content",
      "regex": "(?im)^[ \\t]*[A-Za-z0-9_.\\-]*(?:secret|token|passw(?:or)?d|pwd|api[_-]?key|apikey|private[_-]?key|access[_-]?key|auth[_-]?key|credential)s?[ \\t]*[:=][ \\t]*(?!(?:<<REDACTED|your|<|\\$|\\{|%|xxx|\\*|change[_-]?me|example|placeholder|dummy|none|null|todo|test|sample|redacted|undefined))(?![\\\"'`])[^\\s#<>$\\{\\}\\\"'`]{6,}",
      "description": "Same idea for config files with unquoted values (.properties, .ini, .yml, .toml, .conf, .npmrc, .pypirc).",
      "placeholder": "<<REDACTED:CREDENTIAL>>",
      "action": "redact_value",
      "path_filter": "(?i)(?:^|/)(?:[^/]*\\.(?:properties|ini|cfg|conf|toml|ya?ml|cnf)|\\.npmrc|\\.pypirc)$"
    },
    {
      "id": "ENV_FILE_VALUES",
      "level": "L0",
      "severity": "block",
      "kind": "content",
      "regex": "(?m)^[ \\t]*(?:export[ \\t]+)?[A-Za-z_][A-Za-z0-9_.\\-]*[ \\t]*=[ \\t]*(?!<<REDACTED)(?![\\\"']?[ \\t]*\\r?$)(?![ \\t]*#)[^\\r\\n]+",
      "description": "Any non-empty value in a real .env file. Keep the key names, replace every value.",
      "placeholder": "<<REDACTED:ENV_VALUE>>",
      "action": "redact_value",
      "path_filter": "(?i)(?:^|/)(?!\\.env\\.(?:example|sample|template|dist|defaults?)$)(?:\\.env(?:\\.[^/]*)?|[^/]*\\.env)$"
    },
    {
      "id": "ENV_EXAMPLE_REAL_LOOKING_VALUE",
      "level": "L0",
      "severity": "warn",
      "kind": "content",
      "regex": "(?m)^[ \\t]*(?:export[ \\t]+)?[A-Za-z_][A-Za-z0-9_.\\-]*[ \\t]*=[ \\t]*[\\\"']?(?!<<REDACTED|your|<|xxx|change|example|placeholder|dummy|\\*|\\$|\\{|test|sample)[A-Za-z0-9+/_\\-=.]{20,}",
      "description": "A long, real-looking value in a .env.example style file. Example files should hold placeholders only.",
      "placeholder": "<<REDACTED:ENV_VALUE>>",
      "action": "redact_value",
      "path_filter": "(?i)(?:^|/)\\.env\\.(?:example|sample|template|dist|defaults?)$"
    },
    {
      "id": "BUILD_AND_TOOL_CACHE_DIR",
      "level": "L1",
      "severity": "warn",
      "kind": "path",
      "regex": "(?:^|/)(?:node_modules|Pods|\\.gradle|__pycache__|\\.venv|venv|\\.dart_tool|DerivedData|bower_components|\\.cxx|\\.next|\\.nuxt|\\.expo|\\.pytest_cache|\\.mypy_cache|\\.tox)(?:/|$)",
      "description": "Dependency or tool-cache folder. Not your code. Costs size and adds nothing to the audit.",
      "placeholder": null,
      "action": "exclude_file"
    },
    {
      "id": "BUILD_OUTPUT_DIR_AMBIGUOUS",
      "level": "L1",
      "severity": "warn",
      "kind": "path",
      "regex": "(?:^|/)(?:build|dist|out|target|vendor|obj)/",
      "description": "Folder with a name used for build output or vendored libraries. Exclude it if generated or third-party. Keep it if it is your own hand-written source.",
      "placeholder": null,
      "action": "review"
    },
    {
      "id": "IDE_FOLDER",
      "level": "L1",
      "severity": "warn",
      "kind": "path",
      "regex": "(?:^|/)(?:\\.idea|\\.vscode|\\.vs|\\.fleet)(?:/|$)",
      "description": "Editor settings. May hold local paths, saved database connections and run configs with tokens.",
      "placeholder": null,
      "action": "exclude_file"
    },
    {
      "id": "AI_TOOL_LOCAL_SETTINGS",
      "level": "L1",
      "severity": "warn",
      "kind": "path",
      "regex": "(?i)(?:^|/)\\.(?:claude|cursor|continue)/(?:settings\\.local\\.json|[^/]*\\.local\\.[a-z]+)$",
      "description": "Local AI-tool settings. Can include allow-lists with embedded commands and tokens.",
      "placeholder": null,
      "action": "exclude_file"
    },
    {
      "id": "LOG_FILE",
      "level": "L1",
      "severity": "warn",
      "kind": "path",
      "regex": "(?i)(?:^|/)(?:[^/]*\\.(?:log|hprof)|logs)(?:/|$)",
      "description": "Log or heap dump. Logs hold user data, tokens and hostnames.",
      "placeholder": null,
      "action": "exclude_file"
    },
    {
      "id": "OS_JUNK_FILE",
      "level": "L1",
      "severity": "warn",
      "kind": "filename",
      "regex": "(?i)^(?:\\.DS_Store|Thumbs\\.db|desktop\\.ini)$",
      "description": "Operating-system junk file.",
      "placeholder": null,
      "action": "exclude_file"
    },
    {
      "id": "BUILT_BINARY_FILE",
      "level": "L1",
      "severity": "warn",
      "kind": "filename",
      "regex": "(?i)^[^/]*\\.(?:apk|aab|ipa|jar|aar|war|ear|dex|class|o|a|so|dll|exe|dylib|lib|pyc|wasm)$",
      "description": "Compiled or packaged binary. The audit reads source. Binaries cannot be scanned.",
      "placeholder": null,
      "action": "exclude_file"
    },
    {
      "id": "MINIFIED_BUNDLE_FILE",
      "level": "L1",
      "severity": "warn",
      "kind": "filename",
      "regex": "(?i)^[^/]*\\.min\\.(?:js|css)$",
      "description": "Minified or bundled file. Generated, unreadable, and billed by size.",
      "placeholder": null,
      "action": "exclude_file"
    },
    {
      "id": "EMAIL_ADDRESS",
      "level": "L1",
      "severity": "warn",
      "kind": "content",
      "regex": "(?<![A-Za-z0-9._%+\\-])(?!git@)[A-Za-z0-9._%+\\-]{1,64}@(?!(?:example\\.(?:com|org|net)|localhost|invalid|test)(?![A-Za-z0-9\\-]))[A-Za-z0-9\\-]{1,63}(?:\\.[A-Za-z0-9\\-]{1,63})*\\.[A-Za-z]{2,24}(?![A-Za-z0-9\\-])",
      "description": "Email address.",
      "placeholder": "<<REDACTED:EMAIL>>",
      "action": "redact_value"
    },
    {
      "id": "PHONE_NUMBER_INTL",
      "level": "L1",
      "severity": "warn",
      "kind": "content",
      "regex": "(?<![\\w.+])\\+[1-9]\\d{0,2}[ .\\-]?\\(?\\d{2,4}\\)?(?:[ .\\-]?\\d{2,4}){2,4}(?![\\w])",
      "description": "Phone number in international format.",
      "placeholder": "<<REDACTED:PHONE>>",
      "action": "redact_value"
    },
    {
      "id": "PHONE_NUMBER_US",
      "level": "L1",
      "severity": "warn",
      "kind": "content",
      "regex": "(?<![\\d.\\-])\\(?\\d{3}\\)?[ .\\-]\\d{3}[ .\\-]\\d{4}(?![\\d\\-])",
      "description": "Phone number in US format.",
      "placeholder": "<<REDACTED:PHONE>>",
      "action": "redact_value"
    },
    {
      "id": "IPV4_ADDRESS",
      "level": "L1",
      "severity": "warn",
      "kind": "content",
      "regex": "(?<![\\dA-Za-z.\\-])(?!(?:127\\.|0\\.|255\\.|192\\.0\\.2\\.|198\\.51\\.100\\.|203\\.0\\.113\\.))(?:(?:25[0-5]|2[0-4]\\d|1?\\d?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|1?\\d?\\d)(?![\\d.]*[\\dA-Za-z\\-])",
      "description": "IPv4 address (documentation and loopback ranges are ignored). Private ranges are kept in this rule because they reveal your network.",
      "placeholder": "<<REDACTED:IP_ADDRESS>>",
      "action": "redact_value"
    },
    {
      "id": "IPV6_ADDRESS_FULL",
      "level": "L1",
      "severity": "warn",
      "kind": "content",
      "regex": "(?i)(?<![\\w:])(?:[0-9a-f]{1,4}:){7}[0-9a-f]{1,4}(?![\\w:])",
      "description": "Full-form IPv6 address.",
      "placeholder": "<<REDACTED:IP_ADDRESS>>",
      "action": "redact_value"
    },
    {
      "id": "INTERNAL_HOSTNAME",
      "level": "L1",
      "severity": "warn",
      "kind": "content",
      "regex": "(?<![A-Za-z0-9.\\-])[a-z0-9][a-z0-9\\-]{0,62}(?:\\.[a-z0-9\\-]{1,63})*\\.(?:internal|corp|lan|intranet|local)(?![A-Za-z0-9\\-]|\\.[A-Za-z])",
      "description": "Internal hostname (.internal, .corp, .lan, .intranet, .local). Lowercase names only, to avoid code like obj.internal.",
      "placeholder": "<<REDACTED:INTERNAL_HOST>>",
      "action": "redact_value"
    },
    {
      "id": "HOME_PATH_USER_NAME",
      "level": "L1",
      "severity": "warn",
      "kind": "content",
      "regex": "(?:/Users/|/home/|[A-Za-z]:\\\\+Users\\\\+)(?!(?:Shared|runner|user|username|me|vagrant|ubuntu|app|node|build|circleci|Public|Default|linuxbrew)(?![A-Za-z0-9._\\-]))[A-Za-z0-9._\\-]+",
      "description": "Local user folder path. It contains your account name.",
      "placeholder": "<<REDACTED:HOME_PATH_USER>>",
      "action": "redact_value"
    },
    {
      "id": "AUTHOR_TAG",
      "level": "L1",
      "severity": "warn",
      "kind": "content",
      "regex": "(?i)@author[ \\t]+[^\\s*][^\\r\\n]{1,60}",
      "description": "@author tag with a name.",
      "placeholder": "<<REDACTED:PERSON_NAME>>",
      "action": "redact_value"
    },
    {
      "id": "WALLET_ADDRESS_NEAR_KEYWORD",
      "level": "L1",
      "severity": "warn",
      "kind": "content",
      "regex": "(?i)(?:wallet|owner|user|authority|payer|address|pubkey|account|holder|buyer|seller)[^\\n]{0,30}?(?<![1-9A-HJ-NP-Za-km-z])[1-9A-HJ-NP-Za-km-z]{43,44}(?![1-9A-HJ-NP-Za-km-z])",
      "description": "Solana address (43-44 base58) next to wallet, owner, user or similar words. Public on chain, but it ties the code to a real person. Keep program and token addresses that the code needs.",
      "placeholder": "<<REDACTED:WALLET_ADDRESS>>",
      "action": "pseudonymize"
    },
    {
      "id": "EVM_ADDRESS_NEAR_KEYWORD",
      "level": "L1",
      "severity": "warn",
      "kind": "content",
      "regex": "(?i)(?:wallet|owner|user|account|holder|buyer|seller)[^\\n]{0,30}?(?<![0-9a-fA-F])0x[0-9a-fA-F]{40}(?![0-9a-fA-F])",
      "description": "EVM address next to wallet, owner or user words. Public on chain, but it ties the code to a real person. Keep contract addresses the code needs.",
      "placeholder": "<<REDACTED:WALLET_ADDRESS>>",
      "action": "pseudonymize"
    },
    {
      "id": "GOOGLE_SERVICES_JSON_IDS",
      "level": "L1",
      "severity": "warn",
      "kind": "content",
      "regex": "\\\"(?:project_id|project_number|mobilesdk_app_id|storage_bucket|firebase_url)\\\"\\s*:\\s*\\\"[^\\\"]+\\\"",
      "description": "Firebase project identifiers in google-services.json. Keep package_name. The API key itself is already handled at L0.",
      "placeholder": "<<REDACTED:PROJECT_ID>>",
      "action": "redact_value",
      "path_filter": "(?i)(?:^|/)google-services\\.json$"
    },
    {
      "id": "GOOGLE_SERVICE_INFO_PLIST_IDS",
      "level": "L1",
      "severity": "warn",
      "kind": "content",
      "regex": "<key>(?:PROJECT_ID|GOOGLE_APP_ID|GCM_SENDER_ID|STORAGE_BUCKET|CLIENT_ID|REVERSED_CLIENT_ID|DATABASE_URL)</key>\\s*<string>[^<]+</string>",
      "description": "Firebase project identifiers in GoogleService-Info.plist. The API key itself is already handled at L0.",
      "placeholder": "<<REDACTED:PROJECT_ID>>",
      "action": "redact_value",
      "path_filter": "(?i)(?:^|/)GoogleService-Info\\.plist$"
    },
    {
      "id": "URL_NON_PUBLIC_DOMAIN",
      "level": "L2",
      "severity": "warn",
      "kind": "content",
      "regex": "(?i)https?://(?!(?:[a-z0-9\\-]+\\.)*(?:github\\.com|githubusercontent\\.com|developer\\.android\\.com|android\\.com|google\\.com|googleapis\\.com|w3\\.org|apache\\.org|mozilla\\.org|npmjs\\.org|npmjs\\.com|maven\\.org|gradle\\.org|kotlinlang\\.org|jetbrains\\.com|solana\\.com|anza\\.xyz|stackoverflow\\.com|xmlsoap\\.org|example\\.com|example\\.org|example\\.net|localhost)(?![A-Za-z0-9\\-]))[a-z0-9\\-]+(?:\\.[a-z0-9\\-]+)+",
      "description": "URL on a domain that is not a well-known public site. At L2, replace your own and your customers' domains with aliases (api.alias-3.test). Keep public service endpoints the code depends on.",
      "placeholder": "<<ALIAS:URL_n>>",
      "action": "pseudonymize"
    },
    {
      "id": "ANDROID_APPLICATION_ID_OR_NAMESPACE",
      "level": "L2",
      "severity": "warn",
      "kind": "content",
      "regex": "(?:\\b(?:applicationId|namespace)\\s*(?:=\\s*)?[\\\"'][a-z][a-z0-9_]*(?:\\.[a-z0-9_]+){2,}[\\\"']|<manifest[^>]*\\spackage\\s*=\\s*\\\"[^\\\"]+\\\")",
      "description": "App package name. It usually carries your company name. At L2, alias it everywhere (Gradle, manifest, source folders and package lines) with one consistent alias.",
      "placeholder": "<<ALIAS:PACKAGE_n>>",
      "action": "pseudonymize"
    },
    {
      "id": "COPYRIGHT_HOLDER",
      "level": "L2",
      "severity": "warn",
      "kind": "content",
      "regex": "(?i)(?:copyright|\\(c\\)|\\u00a9)\\s*(?:\\d{4}(?:\\s*[-,]\\s*\\d{4})?\\s*)[A-Za-z][^\\r\\n]{2,60}",
      "description": "Copyright line with a holder name. Often your company.",
      "placeholder": "<<REDACTED:COMPANY_NAME>>",
      "action": "pseudonymize"
    },
    {
      "id": "LITERAL_CUSTOMER_OR_TENANT_ID",
      "level": "L2",
      "severity": "warn",
      "kind": "content",
      "regex": "(?i)(?:customer|client|tenant|account|user|org(?:anization)?)[_-]?id[\\\"']?\\s*[:=]\\s*[\\\"'][A-Za-z0-9\\-_]*\\d[A-Za-z0-9\\-_]{5,}[\\\"']",
      "description": "A literal customer, tenant, account or user identifier. Replace with a made-up one of the same shape.",
      "placeholder": "<<REDACTED:CUSTOMER_ID>>",
      "action": "pseudonymize"
    }
  ]
}
