Skip to content

feat(detectors): add Slack App-Level Token support#5089

Open
deerajcm wants to merge 7 commits into
trufflesecurity:mainfrom
deerajcm:add-slack-app-token
Open

feat(detectors): add Slack App-Level Token support#5089
deerajcm wants to merge 7 commits into
trufflesecurity:mainfrom
deerajcm:add-slack-app-token

Conversation

@deerajcm

@deerajcm deerajcm commented Jun 30, 2026

Copy link
Copy Markdown

Summary

Add detection for Slack App-Level tokens (SVC027) to existing Slack detector.

Changes

  • Add pattern for Slack App-Level tokens: xapp-1-[A-Za-z0-9-]{48,}
  • Update keywords to include xapp- for efficient pre-filtering
  • Add test cases for valid and invalid App-Level token patterns
  • Support lowercase hex characters in token body (previously uppercase only)
  • Reuse existing auth.test endpoint for verification

Detector Details

Type: Slack App-Level Token
Pattern: xapp-1- prefix followed by 48+ alphanumeric characters and hyphens
Verification: Uses existing Slack auth.test API endpoint
Use Case: Authenticate apps at workspace level for Socket Mode connections and app-level functionality

Existing Slack Token Types (Already Supported)

  • xoxb- Bot Token
  • xoxp- User Token
  • xoxa- Workspace Access Token
  • xoxr- Workspace Refresh Token

New Token Type (This PR)

  • xapp-1- App-Level Token (NEW)

Test Results

✅ valid_pattern_with_keyword_slack - PASS (includes App-Level token)
✅ invalid_pattern - PASS

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Bundled proto enum changes (including removing `BrainTrustApiKey` from 1053) and verification paths that probe localhost Docker/Vault or decode Basic Auth credentials increase build and false-positive/operational risk despite following existing detector patterns.
> 
> **Overview**
> This PR expands secret scanning beyond the advertised Slack change: it adds **Slack App-Level tokens** (`xapp-1-…`) to the existing Slack scanner (pattern, `xapp-` keyword, tests) while still using `auth.test` for verification.
> 
> It also introduces **four new detectors** wired into `defaults`: **HTTP Basic Auth** (header regex, base64 decode, username/password in `SecretParts`, always unverified), **Duffel** API tokens (implements the previously stubbed proto entry; verifies only `duffel_test_` against the airlines API), **Vault** tokens (`hvs`/`hvb`/`hvr`/`s.` with optional `lookup-self` against configurable/default Vault URLs), and **Docker Swarm unlock keys** (`SWMKEY-1-…`, with optional HTTP checks to localhost Docker and format-based “verified” fallback).
> 
> **Proto / enum updates** add `BasicAuth`, `Duffel` (no longer “not implemented”), and several other detector IDs while **replacing** `BrainTrustApiKey` at 1053 with unrelated types (`ShippoLiveToken`, etc.) and adding `SlackAppToken` at 1069 even though Slack app tokens are handled under the existing `Slack` detector—worth confirming enum consistency with `DetectorType_DockerSwarmUnlock` used in code vs `DockerSwarmJoinToken` in proto.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit d91d07d59301c3fde5080da68e0f65a6135fd0d9. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

Deeraj CM and others added 6 commits June 22, 2026 10:26
Add detector for HTTP Basic Authentication tokens (BSCAU002).
Detects Authorization: Basic <base64> patterns and decodes them
to extract username:password credentials.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
feat(detectors): add BasicAuth detector
Add detector for Docker Swarm Unlock Keys (DKRSWRM002).
Detects SWMKEY-1-<base64> patterns used to unlock locked
Docker Swarm managers. Validates format and returns verified
status for properly formatted keys.

Docker Swarm unlock keys are 52+ character tokens starting
with SWMKEY-1- prefix followed by base64-encoded data.
These keys are used to unlock encrypted swarm state after
manager node restarts.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add detector for Duffel API tokens (DFL001).
Detects duffel_test_ and duffel_live_ token patterns
used to access Duffel's travel booking API.

Duffel is a travel API platform for booking flights, stays,
and ground transportation. Tokens are 40-60 character strings
with test/live prefixes. Only test tokens are verified
automatically for safety.

Pattern: duffel_(test|live)_[a-zA-Z0-9_-]{40,60}
API Version: v2 (v1 deprecated)
Verification: GET /air/airlines endpoint

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add detector for HashiCorp Vault tokens (TF030).
Detects hvs., hvb., hvr., and legacy s. token formats
used to authenticate with Vault servers.

HashiCorp Vault tokens are used to access secrets, manage
policies, and perform administrative operations. Supports
multiple token formats:
- Service tokens (hvs.): Vault 1.10+ format, 90+ chars
- Batch tokens (hvb.): 138+ chars
- Recovery tokens (hvr.): 138+ chars
- Legacy service tokens (s.): 24+ chars

Pattern detection works for all formats. Verification
attempts to connect to common Vault endpoints but will
show unverified status without accessible server.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add detection for Slack App-Level tokens (SVC027).
Extends existing Slack detector to support xapp-1- token format
used for app-level authentication.

Slack App-Level tokens are used to authenticate apps at the
workspace level, allowing Socket Mode connections and other
app-level functionality. Format: xapp-1-[A-Za-z0-9-]{48,}

Changes:
- Add pattern for App-Level tokens (xapp-1-)
- Update keywords to include "xapp-"
- Add test cases for valid/invalid App-Level tokens
- Supports lowercase hex characters in token body

Verification uses existing auth.test endpoint which works
for all Slack token types including App-Level tokens.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@deerajcm deerajcm requested a review from a team June 30, 2026 07:58
@deerajcm deerajcm requested review from a team as code owners June 30, 2026 07:58
@CLAassistant

CLAassistant commented Jun 30, 2026

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
1 out of 2 committers have signed the CLA.

✅ deerajcm
❌ Deeraj CM


Deeraj CM seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

// Format validation: SWMKEY-1- prefix + base64 (40+ chars after prefix)
if len(token) >= 49 && len(token) >= 9 && token[:9] == "SWMKEY-1-" {
return true, nil
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Format fallback makes verification always return true

High Severity

The format-check fallback in verifyDockerSwarmUnlock always passes for any token matched by the regex, making every detected token Verified = true without actual verification. The regex (SWMKEY-1-[A-Za-z0-9+/]{40,}={0,2}) guarantees a SWMKEY-1- prefix and at least 49 characters, so the condition len(token) >= 49 && len(token) >= 9 && token[:9] == "SWMKEY-1-" is always satisfied. The Verified field loses its meaning entirely — it no longer indicates the secret was confirmed active against a real service.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 21ac218. Configure here.

if err != nil {
continue
}
defer resp.Body.Close()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deferred resp.Body.Close inside loop causes resource leak

Medium Severity

defer resp.Body.Close() is inside a for loop over vaultUrls. In Go, defer executes when the enclosing function returns, not at the end of the loop iteration. If the loop iterates through multiple URLs (e.g., first returns 400 and continues), response bodies from earlier iterations remain open until the function exits. The sibling detector dockerswarmunlock correctly calls resp.Body.Close() directly without defer in its loop.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 21ac218. Configure here.

}

req.Header.Set("Content-Type", "application/json")
req.Body = http.NoBody

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verification request omits the unlock key in body

Medium Severity

The POST request to Docker's /swarm/unlock endpoint never sends the unlock key. The request is created with a nil body and then explicitly set to http.NoBody. The Docker Engine API expects a JSON body containing {"UnlockKey": "SWMKEY-1-..."}. Without it, the API cannot validate the token, so even if the Docker daemon is reachable, verification cannot succeed as intended.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 21ac218. Configure here.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 4 total unresolved issues (including 3 from previous reviews).

Fix All in Cursor

Reviewed by Cursor Bugbot for commit d91d07d. Configure here.

Comment thread proto/detector_type.proto
SpectralOps = 1051;
AWSAppSync = 1052;
BrainTrustApiKey = 1053;
ShippoLiveToken = 1053;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enum value 1053 reassigned, breaking existing detector

High Severity

Protobuf enum value 1053 is reassigned from BrainTrustApiKey to ShippoLiveToken. The existing braintrust detector package still references DetectorType_BrainTrustApiKey, and any previously stored detection results with type 1053 would be silently misinterpreted as ShippoLiveToken. Protobuf enum values are not meant to be reassigned.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit d91d07d. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants