keyhog-core 0.5.73

keyhog-core: shared data model and detector specifications for the KeyHog secret scanner
Documentation
# Docs: https://docs.base.org/
# Format: Base chain RPC endpoints use API keys in URL path or Authorization header
# Verify: no public verification endpoint
# Prefix: none (requires context anchoring)

[detector]
id = "base-api-credentials"
name = "Base Chain API Credentials"
service = "base"
severity = "high"
ml = { match_mode = "lift", entropy_mode = "disabled", weight = 1.0, context_radius_lines = 5 }
match_confidence = { literal_prefix_weight = 0.35, context_anchor_weight = 0.20, entropy_weight = 0.20, high_entropy_partial_weight = 0.12, moderate_entropy_threshold = 3.0, moderate_entropy_weight = 0.05, low_entropy_penalty_floor = 2.0, low_entropy_min_match_length = 10, low_entropy_penalty_multiplier = 0.60, keyword_nearby_weight = 0.10, sensitive_file_weight = 0.10, companion_weight = 0.05, very_high_entropy_margin = 1.2999999999999998, named_anchor_floor = 0.55, assignment_context_multiplier = 1.0, string_literal_context_multiplier = 0.9, unknown_context_multiplier = 0.8, documentation_context_multiplier = 0.3, comment_context_multiplier = 0.4, test_context_multiplier = 0.3, encrypted_context_multiplier = 0.05, soft_context_suppression_threshold = 0.5, encrypted_context_suppression_threshold = 0.8, post_match = { placeholder_multiplier = 0.05, minimum_byte_diversity = 0.1, low_diversity_multiplier = 0.1, maximum_repeat_ratio = 0.8, degenerate_run_min_length = 10, degenerate_repeat_multiplier = 0.1, fixture_path_multiplier = 0.5, ml_context_reapply_below = 0.95 } }
min_confidence = 0.2
keywords = ["base", "BASE", "base.org", "basescan", "base-mainnet"]
# Weak-anchor: the vendor prefix does not tightly bound the captured value (it
# collides with a generic hex/base64 run), so scanner suppression keeps the
# generic shape/entropy gates ENGAGED through this detector-owned flag.
weak_anchor = true
entropy_high = 4.5
entropy_floor = [{ max_len = 24, floor = 3.0 }, { max_len = 40, floor = 2.8 }, { floor = 3.5 }]
canonical_hex_key_material = [{ lengths = [32] }]

[[detector.patterns]]
regex = '(?:base|BASE)[._-]?(?:rpc|RPC)[._-]?(?:url|URL|endpoint)[=:"	\s]+(https?://[a-zA-Z0-9._-]+\.g\.alchemy\.com/v2/[a-zA-Z0-9_-]+)'
description = "Base chain RPC URL with Alchemy API key"
group = 1

[[detector.patterns]]
regex = '(?:base|BASE)[._-]?(?:rpc|RPC)[._-]?(?:url|URL|endpoint)[=:"	\s]+(https?://[a-zA-Z0-9._-]+/base/[a-zA-Z0-9_-]+)'
description = "Base chain RPC URL with embedded access token"
group = 1

[[detector.patterns]]
regex = '(?:base|BASE)[._-]?(?:rpc|RPC)[._-]?(?:url|URL|endpoint)[=:"	\s]+(https?://[a-zA-Z0-9._-]+/8453/[a-zA-Z0-9_-]+)'
description = "Base chain RPC URL with chain ID and API key"
group = 1

[[detector.patterns]]
regex = '(?:base|BASE)[._-]?(?:api|API)[._-]?key[=:"	\s]+([a-f0-9]{32})\b'
description = "Base chain API key (32 hex characters)"
group = 1

[[detector.tests]]
test_positive = "base_api_key=7b3e5d8c1a9f4e2b6c8d3a5e9f1b7c4d"
test_negative = "BASE_API_KEY=short"