rules: - name: Vercel API Token (legacy 24-char) id: kingfisher.vercel.1 pattern: | (?xi) \b vercel (?:.|[\n\r]){0,32}? \b ( [A-Z0-9]{24} ) \b pattern_requirements: min_digits: 3 min_uppercase: 1 min_lowercase: 1 confidence: medium min_entropy: 3.5 validation: type: Http content: request: method: GET url: https://api.vercel.com/v2/user headers: Authorization: "Bearer {{TOKEN}}" response_matcher: - report_response: true - type: StatusMatch status: [200] - type: WordMatch words: - '"user":' - '"email":' match_all_words: true references: - https://vercel.com/kb/guide/how-do-i-use-a-vercel-api-access-token - https://docs.vercel.com/docs/rest-api/reference/welcome#authentication examples: - "vercel-key = DdZV6ZDZW6Vpl7n7JqtrCE5i" - "vercel_token = zyMBA1qVEMAf4UNNZtCAbg6u" - "vercel_api_key = MTg0AW799OY1HmyDdn84or3C" - "vercel_secret = A7n9Xfp3tBz7D0XpOTMWpiOM" - name: Vercel Personal Access Token (vcp_) id: kingfisher.vercel.2 pattern: | (?x) \b ( vcp_(?P[A-Za-z0-9_-]{50})(?P[A-Za-z0-9]{6}) ) \b pattern_requirements: min_digits: 3 checksum: actual: template: "{{ checksum }}" requires_capture: checksum # Vercel token checksum format: Base62(CRC32(body)) padded to 6 chars. # The "body" is the 50-char payload portion after the prefix. expected: "{{ body | crc32 | base62: 6 }}" skip_if_missing: true confidence: medium min_entropy: 3.5 validation: type: Http content: request: method: GET url: https://api.vercel.com/v2/user headers: Authorization: "Bearer {{TOKEN}}" response_matcher: - report_response: true - type: StatusMatch status: [200] - type: WordMatch words: - '"user":' - '"email":' match_all_words: true references: - https://vercel.com/kb/guide/how-do-i-use-a-vercel-api-access-token - https://docs.vercel.com/docs/rest-api/reference/welcome#authentication - https://vercel.com/changelog/new-token-formats-and-secret-scanning examples: - "vcp_35UYJwYZDigYATKhxJUAhPqRhit2Xe3dtiG60LsUTHeklEXDQ94Jafpu" - "vercel_access_token=vcp_4mcjwVDwqtVCVGWCcxRjdzGpkGZ3NkwXZv8ktcoQ0EG0dnjpMP1Rzi71" - name: Vercel Integration Token (vci_) id: kingfisher.vercel.3 pattern: | (?x) \b ( vci_(?P[A-Za-z0-9_-]{50})(?P[A-Za-z0-9]{6}) ) \b pattern_requirements: min_digits: 3 checksum: actual: template: "{{ checksum }}" requires_capture: checksum expected: "{{ body | crc32 | base62: 6 }}" skip_if_missing: true confidence: medium min_entropy: 3.5 validation: type: Http content: request: method: GET url: https://api.vercel.com/v2/user headers: Authorization: "Bearer {{TOKEN}}" response_matcher: - report_response: true - type: StatusMatch status: [200] - type: WordMatch words: - '"user":' match_all_words: false references: - https://vercel.com/docs/integrations/vercel-api-integrations#create-an-access-token - https://vercel.com/changelog/new-token-formats-and-secret-scanning examples: - "Vercel Integration Token: vci_35UYJwYZDigYATKhxJUAhPqRhit2Xe3dtiG60LsUTHeklEXDQ94Jafpu" - name: Vercel App Access Token (vca_) id: kingfisher.vercel.4 pattern: | (?x) \b ( vca_(?P[A-Za-z0-9_-]{50})(?P[A-Za-z0-9]{6}) ) \b pattern_requirements: min_digits: 3 checksum: actual: template: "{{ checksum }}" requires_capture: checksum expected: "{{ body | crc32 | base62: 6 }}" skip_if_missing: true confidence: medium min_entropy: 3.5 validation: type: Http content: request: method: POST url: https://api.vercel.com/login/oauth/userinfo headers: Authorization: "Bearer {{TOKEN}}" response_matcher: - report_response: true - type: StatusMatch status: [200] - type: JsonValid - type: WordMatch words: - '"sub":' match_all_words: true revocation: type: Http content: request: method: POST url: https://api.vercel.com/login/oauth/token/revoke headers: # Requires the Vercel App's client_id and client_secret (Sign in with Vercel). # Docs use NEXT_PUBLIC_VERCEL_APP_CLIENT_ID; support both. Authorization: "Basic {{ NEXT_PUBLIC_VERCEL_APP_CLIENT_ID | default: VERCEL_APP_CLIENT_ID | append: ':' | append: VERCEL_APP_CLIENT_SECRET | b64enc }}" Content-Type: application/x-www-form-urlencoded body: "token={{ TOKEN | url_encode }}" response_matcher: - report_response: true - type: StatusMatch status: [200, 204] references: - https://vercel.com/docs/sign-in-with-vercel/tokens#access-token - https://vercel.com/docs/sign-in-with-vercel/authorization-server-api#user-info-endpoint - https://vercel.com/docs/sign-in-with-vercel/authorization-server-api#revoke-token-endpoint - https://vercel.com/changelog/new-token-formats-and-secret-scanning examples: - "vca_BQuu9ChDu3n6Pfh6YQnCshpoYkWDSFKogLqmBtQ0tC8NAA5rXt340sjz" - name: Vercel App Refresh Token (vcr_) id: kingfisher.vercel.5 pattern: | (?x) \b ( vcr_(?P[A-Za-z0-9_-]{50})(?P[A-Za-z0-9]{6}) ) \b pattern_requirements: min_digits: 3 checksum: actual: template: "{{ checksum }}" requires_capture: checksum expected: "{{ body | crc32 | base62: 6 }}" skip_if_missing: true confidence: medium min_entropy: 3.5 validation: type: Http content: request: method: POST url: https://api.vercel.com/login/oauth/token/introspect headers: Content-Type: application/x-www-form-urlencoded body: "token={{ TOKEN | url_encode }}" response_matcher: - report_response: true - type: StatusMatch status: [200] - type: JsonValid - type: WordMatch words: - '"active":true' match_all_words: true revocation: type: Http content: request: method: POST url: https://api.vercel.com/login/oauth/token/revoke headers: Authorization: "Basic {{ NEXT_PUBLIC_VERCEL_APP_CLIENT_ID | default: VERCEL_APP_CLIENT_ID | append: ':' | append: VERCEL_APP_CLIENT_SECRET | b64enc }}" Content-Type: application/x-www-form-urlencoded body: "token={{ TOKEN | url_encode }}" response_matcher: - report_response: true - type: StatusMatch status: [200, 204] references: - https://vercel.com/docs/sign-in-with-vercel/tokens#refresh-token - https://vercel.com/docs/sign-in-with-vercel/authorization-server-api#token-introspection-endpoint - https://vercel.com/docs/sign-in-with-vercel/authorization-server-api#revoke-token-endpoint - https://vercel.com/changelog/new-token-formats-and-secret-scanning examples: - "vcr_BQuu9ChDu3n6Pfh6YQnCshpoYkWDSFKogLqmBtQ0tC8NAA5rXt340sjz" - name: Vercel AI Gateway API Key (vck_) id: kingfisher.vercel.6 pattern: | (?x) \b ( vck_(?P[A-Za-z0-9_-]{50})(?P[A-Za-z0-9]{6}) ) \b pattern_requirements: min_digits: 3 checksum: actual: template: "{{ checksum }}" requires_capture: checksum expected: "{{ body | crc32 | base62: 6 }}" skip_if_missing: true confidence: medium min_entropy: 3.5 # GET /v1/models returns the catalog without verifying the token (always 200). # Use POST /v1/chat/completions with a minimal request instead; invalid/revoked # keys return 401. validation: type: Http content: request: method: POST url: https://ai-gateway.vercel.sh/v1/chat/completions headers: Authorization: "Bearer {{TOKEN}}" Content-Type: application/json body: '{"model":"openai/gpt-3.5-turbo","messages":[{"role":"user","content":"x"}],"max_tokens":1}' response_matcher: - report_response: true - type: StatusMatch status: [200, 403] - type: JsonValid - type: WordMatch words: - '"choices"' - 'valid credit card' match_all_words: false references: - https://vercel.com/docs/ai-gateway/authentication-and-byok/authentication - https://vercel.com/docs/ai-gateway/openai-compat/rest-api - https://vercel.com/changelog/new-token-formats-and-secret-scanning examples: - "vck_2YkmQj1uHqCVNoUx5a9uvRTe81gmAcln5hoRMPWFBU4tulufUf0OzP2K"