Module: PostHog::MCP::Sanitization::SecretDetection Private
- Defined in:
- lib/posthog/mcp/sanitization.rb
Overview
This module is part of a private API. You should avoid using this module if possible, as it may be removed or be changed in the future.
Last-resort credential detection for bare words.
Constant Summary collapse
- MIN_LENGTH =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
16- MIN_ENTROPY_BITS =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
3.8- MIN_CHAR_CLASSES =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
3- HEX_DIGITS =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
'0123456789abcdefABCDEF'.chars.to_set.freeze
- REJECT_CHARS =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
"()[]{}<>'\"`,;".chars.to_set.freeze
- UUID_RE =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
/\A[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\z/- PATH_WORD_RE =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
/\A[a-z][a-z.]*\z/- PEM_PRIVATE_KEY_HINT =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
A private key is redacted as a whole block, before anything is split into words. The body would mostly be caught word by word anyway - each base64 line is high entropy on its own - but that is a heuristic, and a line that happens to look like a path (two lowercase
/-separated segments) slips through it. Key material should not ride on a heuristic.Matched non-greedily, so several blocks in one value are handled separately, and terminated at end-of-string so a truncated block still loses its body. Covers the
RSA/EC/OPENSSH/ENCRYPTEDvariants and the PGPBLOCKspelling. 'PRIVATE KEY'- PEM_PRIVATE_KEY_BLOCK =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
/ -----BEGIN[A-Z0-9\ ]*\ PRIVATE\ KEY(?:\ BLOCK)?----- .*? (?:-----END[A-Z0-9\ ]*\ PRIVATE\ KEY(?:\ BLOCK)?-----|\z) /mx- KNOWN_SECRET_MAX_SCAN_LENGTH =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
200- KNOWN_SECRET_RE =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
Regexp.union( /sk-ant-[A-Za-z0-9_-]{16,}/, /sk-(?:proj-)?[A-Za-z0-9_-]{20,}/, /hf_[A-Za-z0-9]{34}/, /AKIA[0-9A-Z]{16}/, /(?:ASIA|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ABIA|ACCA)[0-9A-Z]{16}/, /AIza[A-Za-z0-9_-]{35}/, /ya29\.[A-Za-z0-9_-]{20,}/, /do[opr]_v1_[a-f0-9]{64}/, /(?:sk|pk|rk)_(?:live|test)_[A-Za-z0-9]{16,}/, /sq0[a-z]{3}-[A-Za-z0-9_-]{22,43}/, /gh[pousr]_[A-Za-z0-9]{36}/, /github_pat_[A-Za-z0-9_]{20,}/, /gl(?:pat|ptt|rt|soat)-[A-Za-z0-9_-]{20}/, /glsa_[A-Za-z0-9]{32}_[A-Fa-f0-9]{8}/, /xox[abeoprs]-[A-Za-z0-9-]{10,}/, /xapp-[0-9]-[A-Za-z0-9-]{10,}/, /SK[0-9a-fA-F]{32}/, /SG\.[A-Za-z0-9_-]{22}\.[A-Za-z0-9_-]{43}/, /key-[0-9a-f]{32}/, /[0-9a-f]{32}-us[0-9]{1,2}/, /npm_[A-Za-z0-9]{36}/, /pypi-AgEI[A-Za-z0-9_-]{50,}/, /dapi[0-9a-f]{32}/, /dp\.pt\.[A-Za-z0-9]{40,}/, /PMAK-[a-f0-9]{24}-[a-f0-9]{34}/, /lin_api_[A-Za-z0-9]{40}/, /ntn_[A-Za-z0-9]{40,}/, /shp(?:at|ca|pa|ss)_[a-fA-F0-9]{32}/, /NR(?:AK|JS|II|MA|RA)-[A-Za-z0-9]{27}/, /eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{6,}/ )
Class Method Summary collapse
- .high_entropy_secret?(value) ⇒ Boolean private
- .path_or_url?(value) ⇒ Boolean private
-
.redact_private_key_blocks(value) ⇒ String
private
The value with every
-----BEGIN … PRIVATE KEY-----block replaced, leaving surrounding text intact. -
.secret?(value) ⇒ Boolean
private
Whole private-key blocks are handled by SecretDetection.redact_private_key_blocks before a value is ever split, so there is no marker check here: the marker contains a space and could never match a single word anyway.
Class Method Details
.high_entropy_secret?(value) ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 |
# File 'lib/posthog/mcp/sanitization.rb', line 465 def high_entropy_secret?(value) return false if value.include?(' ') || path_or_url?(value) || UUID_RE.match?(value) counts = value.each_char.tally distinct = counts.keys return false if distinct.any? { |ch| REJECT_CHARS.include?(ch) } has_lower = has_upper = has_digit = has_symbol = false hex_only = true distinct.each do |ch| return false if ch.match?(/\s/) case ch when /[[:lower:]]/ has_lower = true hex_only = false unless HEX_DIGITS.include?(ch) when /[[:upper:]]/ has_upper = true hex_only = false unless HEX_DIGITS.include?(ch) when /[[:digit:]]/ has_digit = true else has_symbol = true hex_only = false end end return false if hex_only return false if [has_lower, has_upper, has_digit, has_symbol].count(true) < MIN_CHAR_CLASSES n = value.length.to_f entropy = counts.values.sum do |occurrences| p = occurrences / n -p * Math.log2(p) end entropy >= MIN_ENTROPY_BITS end |
.path_or_url?(value) ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
458 459 460 461 462 463 |
# File 'lib/posthog/mcp/sanitization.rb', line 458 def path_or_url?(value) return true if value.include?('://') || value.include?('\\') return false unless value.include?('/') value.split('/').count { |segment| !segment.empty? && PATH_WORD_RE.match?(segment) } >= 2 end |
.redact_private_key_blocks(value) ⇒ String
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns the value with every -----BEGIN … PRIVATE KEY-----
block replaced, leaving surrounding text intact.
452 453 454 455 456 |
# File 'lib/posthog/mcp/sanitization.rb', line 452 def redact_private_key_blocks(value) return value unless value.include?(PEM_PRIVATE_KEY_HINT) value.gsub(PEM_PRIVATE_KEY_BLOCK, REDACTED_VALUE) end |
.secret?(value) ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Whole private-key blocks are handled by redact_private_key_blocks before a value is ever split, so there is no marker check here: the marker contains a space and could never match a single word anyway.
437 438 439 440 441 442 443 444 445 446 447 448 |
# File 'lib/posthog/mcp/sanitization.rb', line 437 def secret?(value) return false unless value.is_a?(String) && !value.empty? n = value.length return false if n < MIN_LENGTH return true if high_entropy_secret?(value) return KNOWN_SECRET_RE.match?(value) if n <= KNOWN_SECRET_MAX_SCAN_LENGTH false rescue StandardError false end |