diff --git a/pkg/detectors/sqlserver/sqlserver.go b/pkg/detectors/sqlserver/sqlserver.go index 5466578f1..02818ba77 100644 --- a/pkg/detectors/sqlserver/sqlserver.go +++ b/pkg/detectors/sqlserver/sqlserver.go @@ -91,6 +91,26 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result Redacted: detectors.RedactURL(*paramsUnsafe.URL()), } + // msdsn leaves Port zero when the connection string omits it, so only + // qualify the host when a port was actually specified. + extraData := make(map[string]string) + if paramsUnsafe.Host != "" { + if paramsUnsafe.Port > 0 { + extraData["host"] = net.JoinHostPort(paramsUnsafe.Host, strconv.FormatUint(paramsUnsafe.Port, 10)) + } else { + extraData["host"] = paramsUnsafe.Host + } + } + if paramsUnsafe.User != "" { + extraData["username"] = paramsUnsafe.User + } + if paramsUnsafe.Database != "" { + extraData["database"] = paramsUnsafe.Database + } + if len(extraData) > 0 { + s1.ExtraData = extraData + } + if verify { isVerified, err := ping(ctx, paramsUnsafe) diff --git a/pkg/detectors/sqlserver/sqlserver_test.go b/pkg/detectors/sqlserver/sqlserver_test.go index 8c376eb06..2a3808577 100644 --- a/pkg/detectors/sqlserver/sqlserver_test.go +++ b/pkg/detectors/sqlserver/sqlserver_test.go @@ -6,6 +6,9 @@ import ( "testing" "github.com/google/go-cmp/cmp" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/trufflesecurity/trufflehog/v3/pkg/detectors" "github.com/trufflesecurity/trufflehog/v3/pkg/engine/ahocorasick" ) @@ -94,6 +97,59 @@ func TestSqlServer_Pattern(t *testing.T) { } } +func TestSqlServer_ExtraData(t *testing.T) { + tests := []struct { + name string + data string + wantHost string + wantUsername string + wantDatabase string + }{ + { + name: "server with explicit port", + data: `Server=localhost;Port=1433;Initial Catalog=master;User ID=sa;Password=P@ssw0rd!;`, + wantHost: "localhost:1433", + wantUsername: "sa", + wantDatabase: "master", + }, + { + name: "server without port", + data: `Server=dbhost;Initial Catalog=mydb;User ID=admin;Password=secret123;`, + wantHost: "dbhost", + wantUsername: "admin", + wantDatabase: "mydb", + }, + { + name: "xml style parameters", + data: `SERVER=server_name;DATABASE=testdb;user=username;password=badpassword;encrypt=true;`, + wantHost: "server_name", + wantUsername: "username", + wantDatabase: "testdb", + }, + { + name: "no database specified", + data: `Server=localhost;Port=1433;User ID=sa;Password=123;`, + wantHost: "localhost:1433", + wantUsername: "sa", + wantDatabase: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := Scanner{} + results, err := s.FromData(context.Background(), false, []byte(tt.data)) + require.NoError(t, err) + require.NotEmpty(t, results, "expected at least one result") + + r := results[0] + assert.Equal(t, tt.wantHost, r.ExtraData["host"]) + assert.Equal(t, tt.wantUsername, r.ExtraData["username"]) + assert.Equal(t, tt.wantDatabase, r.ExtraData["database"]) + }) + } +} + func TestSqlServer_FromDataWithIgnorePattern(t *testing.T) { s := New( WithIgnorePattern([]string{