From 14b1a6e236851f726dd9d79bec9f88ee50ff7915 Mon Sep 17 00:00:00 2001 From: Cody Rose Date: Fri, 5 Apr 2024 10:26:20 -0400 Subject: [PATCH] Handle inactive Slack account tokens (#2668) This PR updates the Slack detector to accommodate a previously unhandled error type. It also fixes the exiting Slack tests. --- pkg/detectors/slack/slack.go | 8 +++++++- pkg/detectors/slack/slack_test.go | 22 ++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/pkg/detectors/slack/slack.go b/pkg/detectors/slack/slack.go index 63e44fba38cc..dc217a16f82a 100644 --- a/pkg/detectors/slack/slack.go +++ b/pkg/detectors/slack/slack.go @@ -4,9 +4,10 @@ import ( "context" "encoding/json" "fmt" - regexp "github.com/wasilibs/go-re2" "net/http" + regexp "github.com/wasilibs/go-re2" + "github.com/trufflesecurity/trufflehog/v3/pkg/detectors" "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb" @@ -91,6 +92,11 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result // Slack API returns 200 even if the token is invalid. We need to check the error field. } else if authResponse.Error == "invalid_auth" { // The secret is determinately not verified (nothing to do) + } else if authResponse.Error == "account_inactive" { + // "Authentication token is for a deleted user or workspace when using a bot token." + // https://api.slack.com/methods/auth.test) (Per + // https://slack.com/help/articles/360000446446-Manage-deactivated-members-apps-and-integrations, + // reactivating a bot regenerates its tokens, so this candidate is determinately unverified.) } else { err = fmt.Errorf("unexpected error auth response %+v", authResponse.Error) s1.SetVerificationError(err, token) diff --git a/pkg/detectors/slack/slack_test.go b/pkg/detectors/slack/slack_test.go index 28fd42097e35..9d1e77ceb3f5 100644 --- a/pkg/detectors/slack/slack_test.go +++ b/pkg/detectors/slack/slack_test.go @@ -52,6 +52,7 @@ func TestSlack_FromChunk(t *testing.T) { { DetectorType: detectorspb.DetectorType_Slack, Verified: true, + ExtraData: map[string]string{"rotation_guide": "https://howtorotate.com/docs/tutorials/slack/"}, }, }, wantErr: false, @@ -67,10 +68,29 @@ func TestSlack_FromChunk(t *testing.T) { { DetectorType: detectorspb.DetectorType_Slack, Verified: false, + ExtraData: map[string]string{"rotation_guide": "https://howtorotate.com/docs/tutorials/slack/"}, }, }, wantErr: false, }, + { + name: "account_inactive", + s: Scanner{client: common.ConstantResponseHttpClient(200, `{"ok": false, "error": "account_inactive"}`)}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a slack secret %s within", secret)), + verify: true, + }, + wantResults: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_Slack, + Verified: false, + ExtraData: map[string]string{"rotation_guide": "https://howtorotate.com/docs/tutorials/slack/"}, + }, + }, + wantErr: false, + wantVerificationErr: false, + }, { name: "found, would be verified if not for timeout", s: Scanner{client: common.SaneHttpClientTimeOut(1 * time.Microsecond)}, @@ -83,6 +103,7 @@ func TestSlack_FromChunk(t *testing.T) { { DetectorType: detectorspb.DetectorType_Slack, Verified: false, + ExtraData: map[string]string{"rotation_guide": "https://howtorotate.com/docs/tutorials/slack/"}, }, }, wantErr: false, @@ -100,6 +121,7 @@ func TestSlack_FromChunk(t *testing.T) { { DetectorType: detectorspb.DetectorType_Slack, Verified: false, + ExtraData: map[string]string{"rotation_guide": "https://howtorotate.com/docs/tutorials/slack/"}, }, }, wantErr: false,