From 3add34be788a3155da6ef103657586e9656d3043 Mon Sep 17 00:00:00 2001 From: Mick Grove Date: Thu, 26 Jun 2025 15:37:51 -0700 Subject: [PATCH] Added rules for readme, rubygems, salesforce, segment, snyk, pulumi, pubnub --- data/rules/salesforce.yml | 63 ++++++++++++++++++++++++++++++++++++++ data/rules/segment.yml | 62 +++++++++++++++++++++++++++++++++++++ data/rules/snyk.yml | 34 ++++++++++++++++++++ tests/smoke_check_rules.rs | 23 ++++++++++++++ 4 files changed, 182 insertions(+) create mode 100644 data/rules/salesforce.yml create mode 100644 data/rules/segment.yml create mode 100644 data/rules/snyk.yml create mode 100644 tests/smoke_check_rules.rs diff --git a/data/rules/salesforce.yml b/data/rules/salesforce.yml new file mode 100644 index 0000000..d532346 --- /dev/null +++ b/data/rules/salesforce.yml @@ -0,0 +1,63 @@ +rules: + - name: Salesforce Access / Refresh Token + id: kingfisher.salesforce.1 + pattern: | + (?xi) + \b + ( + 00 + [A-Z0-9]{13} + ! + [A-Z0-9._-]{90,120} + ) + min_entropy: 3.3 + confidence: medium + examples: + - 00DE0X0A0M0PeLE!CJoAQOx1GCLf1UIt4UU9y0VOPLUZAYN6I8DsdGEDyHh5cO02egObcAhIDHYiGCfi94c53oFbr4HB.xZfuYRGhvNuxobAAXRe + - | + === Org Description + KEY VALUE + ──────────────── ──────────────────────────────────────────────────────────────────────────────────────────────────────────────── + Access Token 00DE0X0A0M0PeLE!AQcAQH0dMHEXAMPLEzmpkb58urFRkgeBGsxL_QJWwYMfAbUeeG7c1EXAMPLEDUkWe6H34r1AAwOR8B8fLEz6nEXAMPLEAAAA + Client Id PlatformCLI + Connected Status Connected + Id 00D5fORGIDEXAMPLE + Instance Url https://MyDomainName.my.salesforce.com + Username juliet.capulet@empathetic-wolf-g5qddtr.com + validation: + type: Http + content: + request: + headers: + Authorization: 'Bearer {{ TOKEN }}' + method: GET + response_matcher: + - report_response: true + - type: StatusMatch + status: [200] + - type: WordMatch + words: ["DailyApiRequests"] + match_all_words: true + url: "https://{{ INSTANCE }}.my.salesforce.com/services/data/v60.0/limits" + depends_on_rule: + - rule_id: "kingfisher.salesforce.2" + variable: INSTANCE + + - name: Salesforce Instance URL + id: kingfisher.salesforce.2 + pattern: | + (?xi) + \b + (?:https?://)? + ( + [0-9A-Z-]{5,128} + ) + \. + my\.salesforce\.com + \b + min_entropy: 2.5 + confidence: medium + visible: false + examples: + - https://example123.my.salesforce.com + - mydomainname.my.salesforce.com \ No newline at end of file diff --git a/data/rules/segment.yml b/data/rules/segment.yml new file mode 100644 index 0000000..1a2518f --- /dev/null +++ b/data/rules/segment.yml @@ -0,0 +1,62 @@ +rules: + - name: Segment Public API Token + id: kingfisher.segment.1 + pattern: | + (?xi) + \b + ( + sgp_[A-Z0-9_-]{60,70} + ) + \b + min_entropy: 3.3 + confidence: medium + examples: + - sgp_pOqmnKCOAdIxlEbeRLlJKUOE4ravQJ3ZEijxzK4bpPrWaMNPP35kz4OU7ZVsDtgU + validation: + type: Http + content: + request: + headers: + Authorization: "Bearer {{ TOKEN }}" + method: GET + response_matcher: + - report_response: true + - status: + - 200 + type: StatusMatch + url: https://api.segmentapis.com/ + references: + - https://segment.com/docs/api/public-api/ + - https://segment.com/blog/how-segment-proactively-protects-customer-api-tokens/ + + - name: Segment API Key + id: kingfisher.segment.2 + pattern: | + (?xi) + \b + (?:segment|sgmt) + (?:.|[\n\r]){0,16}? + (?:SECRET|PRIVATE|ACCESS|KEY|TOKEN) + (?:.|[\n\r]){0,16}? + \b + ( + [A-Z0-9_-]{40,50}\.[A-Z0-9_-]{40,50} + ) + \b + min_entropy: 3.3 + confidence: medium + examples: + - segment_token=FYbcC23QtDKym0b_bapKDaYKcIv5Ggu0B9icU9cfVud.1mSaWEYOh1GIKw11-VVtS3TVXzI04BkCvyijbHWdZK7 + validation: + type: Http + content: + request: + headers: + Authorization: "Bearer {{ TOKEN }}" + method: GET + response_matcher: + - report_response: true + - status: + - 200 + type: StatusMatch + url: https://api.segmentapis.com/ \ No newline at end of file diff --git a/data/rules/snyk.yml b/data/rules/snyk.yml new file mode 100644 index 0000000..dfadaaa --- /dev/null +++ b/data/rules/snyk.yml @@ -0,0 +1,34 @@ +rules: + - name: Snyk API Key + id: kingfisher.snyk.1 + pattern: | + (?xi) + \b + snyk + (?:.|[\n\r]){0,32}? + (?:SECRET|PRIVATE|ACCESS|KEY|TOKEN) + (?:.|[\n\r]){0,32}? + \b + ( + [A-Z0-9]{8}-(?:[A-Z0-9]{4}-){3}[A-Z0-9]{12} + ) + min_entropy: 3.5 + examples: + - snyk_token = 123e4567-e89b-12d3-a456-426614174000 + - snyk_key = 123e4567-e89b-12d3-a456-426614174abc + validation: + type: Http + content: + request: + method: GET + url: "https://api.snyk.io/rest/self?version=2024-10-15" + headers: + Authorization: "Bearer {{ TOKEN }}" + Accept: application/json + response_matcher: + - report_response: true + - type: StatusMatch + status: [200] + - type: WordMatch + words: ['"username"'] + match_all_words: true \ No newline at end of file diff --git a/tests/smoke_check_rules.rs b/tests/smoke_check_rules.rs new file mode 100644 index 0000000..d220285 --- /dev/null +++ b/tests/smoke_check_rules.rs @@ -0,0 +1,23 @@ +// tests/smoke_check_rules.rs +use std::process::Command; + +use assert_cmd::prelude::*; +use predicates::prelude::*; + + +#[test] +fn check_rules() -> anyhow::Result<()> { + + // ── run kingfisher ──────────────────────────────────────────────── + Command::cargo_bin("kingfisher")? + .args([ + "rules", + "check", + "--no-update-check", // skip update check to avoid network calls + ]) + .assert() + .code(0) // no findings present + .stdout(predicate::str::contains("All rules passed validation successfully")); + + Ok(()) +}