added rules

This commit is contained in:
Mick Grove 2026-03-28 22:39:31 -07:00
commit 2265d2b1f0
7 changed files with 555 additions and 0 deletions

6
NOTICE
View file

@ -47,10 +47,16 @@ Certain detection rules:
* crates/kingfisher-rules/data/rules/instagram.yml
* crates/kingfisher-rules/data/rules/iterable.yml
* crates/kingfisher-rules/data/rules/lokalise.yml
* crates/kingfisher-rules/data/rules/azure-notification-hub.yml
* crates/kingfisher-rules/data/rules/firebase.yml
* crates/kingfisher-rules/data/rules/helpscout.yml
* crates/kingfisher-rules/data/rules/kubernetes.yml
* crates/kingfisher-rules/data/rules/pendo.yml
* crates/kingfisher-rules/data/rules/razorpay.yml
* crates/kingfisher-rules/data/rules/spotify.yml
* crates/kingfisher-rules/data/rules/wakatime.yml
* crates/kingfisher-rules/data/rules/zapier.yml
* crates/kingfisher-rules/data/rules/zendesk.yml
are derived in part from Titus (https://github.com/praetorian-inc/titus),
which is licensed under the Apache License, Version 2.0.

View file

@ -0,0 +1,159 @@
rules:
- name: Azure Notification Hub Namespace Host
id: kingfisher.azure.notificationhub.1
pattern: |
(?xi)
\b
(?:
endpoint
\s*=\s*
sb://
|
notification
(?:.|[\n\r]){0,48}?
https://
)
(
[a-z0-9]
[a-z0-9-]{1,62}
\.servicebus\.windows\.net
)
(?:/|;|\b)
min_entropy: 2.0
confidence: medium
visible: false
examples:
- Endpoint=sb://acme-push.servicebus.windows.net/;SharedAccessKeyName=DefaultListenSharedAccessSignature;SharedAccessKey=VGhpcytpcythK3Rlc3Qra2V5K3ZhbHVlLzEyMzQ1Njc4OTA=
- 'notificationHubEndpoint: "https://mobile-prod.servicebus.windows.net"'
references:
- https://learn.microsoft.com/en-us/rest/api/notificationhubs/use-rest-api-backend
- name: Azure Notification Hub Name
id: kingfisher.azure.notificationhub.2
pattern: |
(?xi)
\b
(?:
notification
(?:hub)?
(?:name|path)
|
hub
(?:name|path)
)
\s*[:=]\s*
["']?
(
[A-Za-z0-9]
[A-Za-z0-9._-]{1,127}
)
["']?
\b
min_entropy: 2.0
confidence: medium
visible: false
examples:
- NotificationHubPath=my-mobile-hub
- 'notificationHubName: "android-prod"'
references:
- https://learn.microsoft.com/en-us/azure/notification-hubs/create-notification-hub-portal
- name: Azure Notification Hub SAS Key Name
id: kingfisher.azure.notificationhub.3
pattern: |
(?xi)
\b
SharedAccessKeyName
\s*[:=]\s*
["']?
(
[A-Za-z]
[A-Za-z0-9_-]{2,63}
)
["']?
\b
min_entropy: 2.0
confidence: medium
visible: false
examples:
- SharedAccessKeyName=DefaultListenSharedAccessSignature
- '"SharedAccessKeyName": "DefaultFullSharedAccessSignature"'
references:
- https://learn.microsoft.com/en-us/azure/notification-hubs/notification-hubs-push-notification-security
- name: Azure Notification Hub Access Key
id: kingfisher.azure.notificationhub.4
pattern: |
(?xi)
(?:
(?:notification\s*hub|Endpoint\s*=\s*sb://[a-z0-9-]{2,63}\.servicebus\.windows\.net/?)
(?:.|[\n\r]){0,160}?
SharedAccessKey
\s*[:=]\s*
["']?
(
[A-Za-z0-9+/]{32,88}={0,2}
)
|
\b
(?:hubAccessKey|notificationHub(?:Access)?Key)
\b
\s*[:=]\s*
["']?
(
[A-Za-z0-9+/]{32,88}={0,2}
)
)
["']?
(?:[^A-Za-z0-9+/=]|$)
pattern_requirements:
min_digits: 2
min_uppercase: 1
min_lowercase: 1
ignore_if_contains:
- example
- sample
- document
- placeholder
min_entropy: 3.7
confidence: medium
examples:
- Endpoint=sb://acme-push.servicebus.windows.net/;SharedAccessKeyName=DefaultListenSharedAccessSignature;SharedAccessKey=Q29udG9zb1Rlc3RLZXkrMTIzNDU2Nzg5MC9BQkNERUZHSEk=
- |
const config = {
notificationHubName: "android-prod",
hubAccessKey: "U2FmZUtleVZhbHVlKzEyMzQ1Njc4OTBBQkNERUYrLz09"
};
references:
- https://learn.microsoft.com/en-us/azure/notification-hubs/notification-hubs-push-notification-security
- https://learn.microsoft.com/en-us/rest/api/notificationhubs/use-rest-api-backend
depends_on_rule:
- rule_id: kingfisher.azure.notificationhub.1
variable: NH_HOST
- rule_id: kingfisher.azure.notificationhub.2
variable: NH_HUB
- rule_id: kingfisher.azure.notificationhub.3
variable: NH_KEY_NAME
validation:
type: Http
content:
request:
method: GET
url: 'https://{{ NH_HOST }}/{{ NH_HUB }}/registrations/?api-version=2015-01'
headers:
Accept: application/atom+xml
Authorization: |
{%- assign uri = "https://" | append: NH_HOST | append: "/" | append: NH_HUB | append: "/registrations/?api-version=2015-01" -%}
{%- assign se = "" | unix_timestamp | plus: 300 -%}
{%- capture to_sign -%}{{ uri | url_encode }}
{{ se }}{%- endcapture -%}
{%- capture auth -%}SharedAccessSignature sr={{ uri | url_encode }}&sig={{ to_sign | hmac_sha256: TOKEN | url_encode }}&se={{ se }}&skn={{ NH_KEY_NAME | url_encode }}{%- endcapture -%}
{{ auth | strip_newlines }}
response_matcher:
- report_response: true
- type: StatusMatch
status: [200]
- type: XmlValid
- type: WordMatch
words:
- "<feed"

View file

@ -0,0 +1,58 @@
rules:
- name: Firebase Cloud Messaging Server Key
id: kingfisher.firebase.1
pattern: |
(?x)
\b
(
AAAA[A-Za-z0-9_-]{7}
:
APA91b[A-Za-z0-9_-]{120,180}
)
(?:[^A-Za-z0-9_-]|$)
pattern_requirements:
min_digits: 2
min_uppercase: 1
min_lowercase: 1
ignore_if_contains:
- example
- sample
- placeholder
- your_key_here
min_entropy: 4.0
confidence: medium
examples:
- FCM_SERVER_KEY=AAAAA1b2CdE:APA91bAbCdEfGhIjKlMnOpQrStUvWxYz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-AaBbCcDdEeFfGgHhIiJj
- 'firebase_server_key: "AAAAQ1w2ErT:APA91bZaYxWvUtSrQpOnMlKjIhGfEdCbA9876543210ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-MmNnOoPpQqRrSsTtUuVv"'
references:
- https://firebase.google.com/docs/cloud-messaging/migrate-v1
# FCM legacy server keys no longer have a safe token-only validation path.
# HTTP v1 requires OAuth2 access tokens from service accounts rather than the legacy key itself.
- name: Firebase Cloud Messaging Device Token
id: kingfisher.firebase.2
pattern: |
(?x)
\b
(
[A-Za-z0-9_-]{22}
:
APA91b[A-Za-z0-9_-]{120,180}
)
(?:[^A-Za-z0-9_-]|$)
pattern_requirements:
min_digits: 2
min_uppercase: 1
min_lowercase: 1
ignore_if_contains:
- example
- sample
- placeholder
min_entropy: 4.0
confidence: medium
examples:
- FCM_DEVICE_TOKEN=AbCdEfGhIjKlMnOpQrStUv:APA91bZaYxWvUtSrQpOnMlKjIhGfEdCbA9876543210ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-AaBbCcDdEeFfGgHhIiJj
- 'registrationToken: "ZyXwVuTsRqPoNmLkJiHgFe:APA91bAbCdEfGhIjKlMnOpQrStUvWxYz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-KkLlMmNnOoPpQqRrSs"'
references:
- https://firebase.google.com/docs/cloud-messaging/manage-tokens
# Registration tokens cant be safely live-validated using only the token value.

View file

@ -0,0 +1,82 @@
rules:
- name: Help Scout Client ID
id: kingfisher.helpscout.1
pattern: |
(?xi)
\b
(?:help[\s_-]?scout|helpscout)
(?:.|[\n\r]){0,48}?
(?:client[\s_.-]*id|app[\s_.-]*id|application[\s_.-]*id)
(?:.|[\n\r]){0,16}?
(
[A-Za-z0-9]{10,40}
)
\b
pattern_requirements:
min_digits: 1
min_uppercase: 1
min_lowercase: 1
min_entropy: 3.1
confidence: medium
visible: false
examples:
- HELPSCOUT_CLIENT_ID=Ab12Cd34Ef56Gh78Ij90
- 'helpscout_app_id: "a1B2c3D4e5F6g7H8i9J0K1L2"'
references:
- https://developer.helpscout.com/mailbox-api/
- name: Help Scout OAuth Client Secret
id: kingfisher.helpscout.2
pattern: |
(?xi)
\b
(?:help[\s_-]?scout|helpscout)
(?:.|[\n\r]){0,48}?
(?:
client[\s_.-]*secret
|
app[\s_.-]*secret
|
oauth[\s_.-]*secret
)
(?:.|[\n\r]){0,16}?
(
[A-Za-z0-9]{24,64}
)
\b
pattern_requirements:
min_digits: 2
min_uppercase: 1
min_lowercase: 1
ignore_if_contains:
- example
- placeholder
- yoursecret
min_entropy: 3.7
confidence: medium
examples:
- HELPSCOUT_CLIENT_SECRET=a3B8f29E4d1C6a0578e23D9f41b6C8e2
- 'helpscout_secret: "E7d2A1f849c3B05d6e81F2a794c3D5b0"'
references:
- https://developer.helpscout.com/mailbox-api/
depends_on_rule:
- rule_id: kingfisher.helpscout.1
variable: CLIENT_ID
validation:
type: Http
content:
request:
method: POST
url: https://api.helpscout.net/v2/oauth2/token
headers:
Content-Type: application/x-www-form-urlencoded
Accept: application/json
body: 'grant_type=client_credentials&client_id={{ CLIENT_ID | url_encode }}&client_secret={{ TOKEN | url_encode }}'
response_matcher:
- report_response: true
- type: StatusMatch
status: [200]
- type: JsonValid
- type: WordMatch
words:
- '"access_token"'

View file

@ -0,0 +1,118 @@
rules:
- name: Kubernetes API Server URL
id: kingfisher.kubernetes.1
pattern: |
(?xi)
\b
(?:
server
|
kube(?:rnetes)?(?:_api)?_server
|
api_server
)
\s*[:=]\s*
["']?
(
https://
(?:
\[[0-9a-f:.]+\]
|
[a-z0-9]
[a-z0-9.-]{1,253}
)
(?::\d{2,5})?
)
["']?
min_entropy: 2.0
confidence: medium
visible: false
examples:
- "server: https://10.96.0.1:443"
- KUBE_API_SERVER=https://api.cluster.example.com:6443
references:
- https://kubernetes.io/docs/reference/access-authn-authz/authentication/
- name: Kubernetes Bootstrap Token
id: kingfisher.kubernetes.2
pattern: |
(?xi)
\b
(?:
bootstrap(?:[-_ ]token)?
|
tls[-_ ]bootstrap[-_ ]token
)
(?:.|[\n\r]){0,12}?
(
[a-z0-9]{6}
\.
[a-z0-9]{16}
)
\b
pattern_requirements:
min_digits: 2
min_entropy: 3.2
confidence: medium
examples:
- BOOTSTRAP_TOKEN=be8dfd.da8a689a46edc282
- --tls-bootstrap-token abcdef.1234567890abcdef
references:
- https://kubernetes.io/docs/reference/access-authn-authz/bootstrap-tokens/
depends_on_rule:
- rule_id: kingfisher.kubernetes.1
variable: KUBE_API_SERVER
validation:
type: Http
content:
request:
method: GET
url: '{{ KUBE_API_SERVER }}/api/v1/namespaces?limit=1'
headers:
Accept: application/json
Authorization: 'Bearer {{ TOKEN }}'
response_matcher:
- report_response: true
- type: StatusMatch
status: [200, 403]
- type: JsonValid
- name: Kubernetes Bootstrap Token Pair
id: kingfisher.kubernetes.3
pattern: |
(?xis)
\btoken-id\b
\s*:\s*
(?P<TOKEN_ID>[a-z0-9]{6})
(?:.|[\n\r]){0,24}?
\btoken-secret\b
\s*:\s*
(?P<TOKEN_SECRET>[a-z0-9]{16})
\b
pattern_requirements:
min_digits: 2
min_entropy: 2.8
confidence: medium
examples:
- |
token-id: 07402b
token-secret: f395accd245ae53d
references:
- https://kubernetes.io/docs/reference/access-authn-authz/bootstrap-tokens/
depends_on_rule:
- rule_id: kingfisher.kubernetes.1
variable: KUBE_API_SERVER
validation:
type: Http
content:
request:
method: GET
url: '{{ KUBE_API_SERVER }}/api/v1/namespaces?limit=1'
headers:
Accept: application/json
Authorization: 'Bearer {{ TOKEN_ID }}.{{ TOKEN_SECRET }}'
response_matcher:
- report_response: true
- type: StatusMatch
status: [200, 403]
- type: JsonValid

View file

@ -0,0 +1,30 @@
rules:
- name: Zapier Webhook URL
id: kingfisher.zapier.1
pattern: |
(?x)
\b
(
https://hooks\.zapier\.com/hooks/catch/
[0-9]{5,10}
/
[a-z0-9]{5,12}
/?
)
min_entropy: 3.4
confidence: medium
examples:
- ZAPIER_WEBHOOK=https://hooks.zapier.com/hooks/catch/11595998/3ouwv7m/
- webhook_url="https://hooks.zapier.com/hooks/catch/2929690/ztd17n/"
references:
- https://help.zapier.com/hc/en-us/articles/8496288690317-Trigger-Zaps-from-webhooks
validation:
type: Http
content:
request:
method: GET
url: '{{ TOKEN }}'
response_matcher:
- report_response: true
- type: StatusMatch
status: [200]

View file

@ -0,0 +1,102 @@
rules:
- name: Zendesk Subdomain
id: kingfisher.zendesk.1
pattern: |
(?xi)
\b
(
[a-z0-9]
[a-z0-9-]{1,62}
\.zendesk\.com
)
\b
min_entropy: 2.0
confidence: medium
visible: false
examples:
- acme-support.zendesk.com
- helpdesk-prod.zendesk.com
references:
- https://developer.zendesk.com/api-reference/introduction/doc-conventions/
- name: Zendesk Account Email
id: kingfisher.zendesk.2
pattern: |
(?xi)
\b
(?:zendesk|zd)
(?:.|[\n\r]){0,32}?
(?:email|user(?:name)?)
(?:.|[\n\r]){0,12}?
(
[A-Za-z0-9._%+\-]+
@
[A-Za-z0-9.\-]+\.[A-Za-z]{2,}
)
\b
min_entropy: 2.0
confidence: medium
visible: false
examples:
- ZENDESK_EMAIL=agent@example.com
- 'zendesk_user: "support.bot@example.org"'
references:
- https://developer.zendesk.com/api-reference/introduction/security-and-auth/
- name: Zendesk API Token
id: kingfisher.zendesk.3
pattern: |
(?xi)
\b
(?:zendesk|zd)
(?:.|[\n\r]){0,48}?
(?:
api[\s_.-]*token
|
token
|
api[\s_.-]*key
)
(?:.|[\n\r]){0,16}?
(
[A-Za-z0-9]{40}
)
\b
pattern_requirements:
min_digits: 2
min_uppercase: 1
min_lowercase: 1
ignore_if_contains:
- example
- placeholder
- yourtoken
min_entropy: 3.8
confidence: medium
examples:
- ZENDESK_API_TOKEN=a3B8f29E4d1C6a0578e23D9f41b6C8e2qR7tY4uI
- zendesk_token="E7d2A1f849c3B05d6e81F2a794c3D5b0pQ8wX1zK"
references:
- https://developer.zendesk.com/api-reference/introduction/security-and-auth/
- https://developer.zendesk.com/api-reference/ticketing/account-configuration/current_user/
depends_on_rule:
- rule_id: kingfisher.zendesk.1
variable: ZENDESK_SUBDOMAIN
- rule_id: kingfisher.zendesk.2
variable: ZENDESK_EMAIL
validation:
type: Http
content:
request:
method: GET
url: 'https://{{ ZENDESK_SUBDOMAIN }}/api/v2/users/me.json'
headers:
Accept: application/json
Authorization: 'Basic {{ ZENDESK_EMAIL | append: "/token:" | append: TOKEN | b64enc }}'
response_matcher:
- report_response: true
- type: StatusMatch
status: [200]
- type: JsonValid
- type: WordMatch
words:
- '"user"'