[INS-243] Fix jdbc detector detecting incomplete connection string and fixed invalid… (#4636)
Lint / golangci-lint (push) Waiting to run
Lint / semgrep (push) Waiting to run
Release / Release (push) Waiting to run
Scan for secrets / test (push) Waiting to run
Test / test (push) Waiting to run
Test / test-community (push) Waiting to run

* Fix jdbc detector detecting incomplete conn string and fixed invalid parsing of sql server string

* [INS-165] Jdbc detector integration tests fix (#4637)

* [INS-165] Fix Jdbc tests and updated the deprecated code
This commit is contained in:
Muneeb Ullah Khan
2026-01-16 15:18:40 +05:00
committed by GitHub
parent b924c0bfbe
commit 116e717154
8 changed files with 81 additions and 22 deletions
+2 -1
View File
@@ -50,7 +50,8 @@ var _ detectors.Detector = (*Scanner)(nil)
var _ detectors.CustomFalsePositiveChecker = (*Scanner)(nil)
var (
keyPat = regexp.MustCompile(`(?i)jdbc:[\w]{3,10}:[^\s"'<>,(){}[\]&]{10,512}`)
// Matches typical JDBC connection strings amd ingores any special character at the end
keyPat = regexp.MustCompile(`(?i)jdbc:[\w]{3,10}:[^\s"'<>,{}[\]]{10,511}[A-Za-z0-9]`)
)
// Keywords are used for efficiently pre-filtering chunks.
+18 -6
View File
@@ -29,8 +29,8 @@ func TestJdbcVerified(t *testing.T) {
postgresUser := gofakeit.Username()
postgresPass := gofakeit.Password(true, true, true, false, false, 10)
postgresDB := gofakeit.Word()
postgresContainer, err := postgres.RunContainer(ctx,
testcontainers.WithImage("postgres:13-alpine"),
postgresContainer, err := postgres.Run(ctx,
"postgres:13-alpine",
postgres.WithDatabase(postgresDB),
postgres.WithUsername(postgresUser),
postgres.WithPassword(postgresPass),
@@ -56,8 +56,8 @@ func TestJdbcVerified(t *testing.T) {
mysqlUser := gofakeit.Username()
mysqlPass := gofakeit.Password(true, true, true, false, false, 10)
mysqlDatabase := gofakeit.Word()
mysqlC, err := mysql.RunContainer(ctx,
mysql.WithDatabase(mysqlDatabase),
mysqlC, err := mysql.Run(ctx,
"mysql:8.0.36",
mysql.WithUsername(mysqlUser),
mysql.WithPassword(mysqlPass),
)
@@ -79,8 +79,8 @@ func TestJdbcVerified(t *testing.T) {
sqlServerPass := gofakeit.Password(true, true, true, false, false, 10)
sqlServerDatabase := "master"
mssqlContainer, err := mssql.RunContainer(ctx,
testcontainers.WithImage("mcr.microsoft.com/azure-sql-edge"),
mssqlContainer, err := mssql.Run(ctx,
"mcr.microsoft.com/azure-sql-edge",
mssql.WithAcceptEULA(),
mssql.WithPassword(sqlServerPass),
)
@@ -125,6 +125,10 @@ func TestJdbcVerified(t *testing.T) {
Verified: true,
Redacted: fmt.Sprintf("jdbc:postgresql://%s:%s/%s?sslmode=disable&password=%s&user=%s",
postgresHost, postgresPort.Port(), postgresDB, strings.Repeat("*", len(postgresPass)), postgresUser),
AnalysisInfo: map[string]string{
"connection_string": fmt.Sprintf("jdbc:postgresql://%s:%s/%s?sslmode=disable&password=%s&user=%s",
postgresHost, postgresPort.Port(), postgresDB, postgresPass, postgresUser),
},
},
},
wantErr: false,
@@ -143,6 +147,10 @@ func TestJdbcVerified(t *testing.T) {
Verified: true,
Redacted: fmt.Sprintf(`jdbc:mysql://%s:%s@tcp(%s:%s)/%s`,
mysqlUser, strings.Repeat("*", len(mysqlPass)), mysqlHost, mysqlPort.Port(), mysqlDatabase),
AnalysisInfo: map[string]string{
"connection_string": fmt.Sprintf(`jdbc:mysql://%s:%s@tcp(%s:%s)/%s`,
mysqlUser, mysqlPass, mysqlHost, mysqlPort.Port(), mysqlDatabase),
},
},
},
wantErr: false,
@@ -161,6 +169,10 @@ func TestJdbcVerified(t *testing.T) {
Verified: true,
Redacted: fmt.Sprintf("jdbc:sqlserver://odbc:server=%s;port=%s;database=%s;password=%s",
sqlServerHost, sqlServerPort.Port(), sqlServerDatabase, strings.Repeat("*", len(sqlServerPass))),
AnalysisInfo: map[string]string{
"connection_string": fmt.Sprintf("jdbc:sqlserver://odbc:server=%s;port=%s;database=%s;password=%s",
sqlServerHost, sqlServerPort.Port(), sqlServerDatabase, sqlServerPass),
},
},
},
wantErr: false,
+10 -2
View File
@@ -40,6 +40,8 @@ func TestJdbc_Pattern(t *testing.T) {
<jdbc-url>jdbc:mysql:localhost:3306/mydatabase</jdbc-url>
<jdbc-url>jdbc:sqlserver://x.x.x.x:1433;databaseName=MY-DB;user=MY-USER;password=MY-PASSWORD;encrypt=false</jdbc-url>
<jdbc-url>jdbc:sqlserver://localhost:1433;databaseName=AdventureWorks</jdbc-url>
<jdbc-url>(jdbc:mysql://testuser:testpassword@tcp(localhost:1521)/testdb)</jdbc-url>
<jdbc-url>jdbc:postgresql://localhost:1521/testdb?sslmode=disable&password=testpassword&user=testuser&</jdbc-url>
<working-dir>$ProjectFileDir$</working-dir>
</data-source>
</component>
@@ -50,6 +52,8 @@ func TestJdbc_Pattern(t *testing.T) {
"jdbc:mysql:localhost:3306/mydatabase",
"jdbc:sqlserver://x.x.x.x:1433;databaseName=MY-DB;user=MY-USER;password=MY-PASSWORD;encrypt=false",
"jdbc:sqlserver://localhost:1433;databaseName=AdventureWorks",
"jdbc:mysql://testuser:testpassword@tcp(localhost:1521)/testdb",
"jdbc:postgresql://localhost:1521/testdb?sslmode=disable&password=testpassword&user=testuser",
},
},
{
@@ -64,8 +68,10 @@ func TestJdbc_Pattern(t *testing.T) {
"jdbc:oracle:thin:@host:1521:db",
"jdbc:mysql://host:3306/db,other_param",
"jdbc:db2://host:50000/db?param=1"
]
}`,
"jdbc:postgresql://localhost:1521/testdb?sslmode=disable&password=testpassword&user=testuser"
"jdbc:mysql://testuser:testpassword@tcp(localhost:1521)/testdb"
]
}`,
want: []string{
"jdbc:postgresql://localhost:5432/mydb",
"jdbc:mysql://user:pass@host:3306/db?param=1",
@@ -73,6 +79,8 @@ func TestJdbc_Pattern(t *testing.T) {
"jdbc:oracle:thin:@host:1521:db",
"jdbc:mysql://host:3306/db",
"jdbc:db2://host:50000/db?param=1",
"jdbc:postgresql://localhost:1521/testdb?sslmode=disable&password=testpassword&user=testuser",
"jdbc:mysql://testuser:testpassword@tcp(localhost:1521)/testdb",
},
},
{
+2 -1
View File
@@ -23,7 +23,8 @@ func TestMySQL(t *testing.T) {
ctx := context.Background()
mysqlC, err := mysql.RunContainer(ctx,
mysqlC, err := mysql.Run(ctx,
"mysql:8.0.36",
mysql.WithDatabase(mysqlDatabase),
mysql.WithUsername(mysqlUser),
mysql.WithPassword(mysqlPass),
@@ -6,7 +6,6 @@ package jdbc
import (
"context"
"fmt"
"log"
"testing"
"time"
@@ -34,8 +33,8 @@ func TestPostgres(t *testing.T) {
t.Log("dbName: ", dbName)
ctx := context.Background()
postgresContainer, err := postgres.RunContainer(ctx,
testcontainers.WithImage("postgres:13-alpine"),
postgresContainer, err := postgres.Run(ctx,
"postgres:13-alpine",
postgres.WithDatabase(dbName),
postgres.WithUsername(user),
postgres.WithPassword(pass),
@@ -56,10 +55,6 @@ func TestPostgres(t *testing.T) {
if err != nil {
t.Fatal(err)
}
if err != nil {
log.Fatalf("failed to start container: %s", err)
}
defer postgresContainer.Terminate(ctx)
tests := []struct {
+5
View File
@@ -73,6 +73,11 @@ func parseSqlServer(ctx logContext.Context, subname string) (JDBC, error) {
continue
}
// incase there is a bridge between jdbc and some driver like "odbc", and conn string looks like this odbc:server
if split := strings.Split(key, ":"); len(split) > 1 {
key = split[1]
}
switch strings.ToLower(key) {
case "password", "spring.datasource.password", "pwd":
password = value
@@ -10,8 +10,8 @@ import (
"github.com/brianvoe/gofakeit/v7"
"github.com/stretchr/testify/assert"
"github.com/testcontainers/testcontainers-go"
"github.com/testcontainers/testcontainers-go/modules/mssql"
logContext "github.com/trufflesecurity/trufflehog/v3/pkg/context"
)
func TestSqlServer(t *testing.T) {
@@ -21,8 +21,8 @@ func TestSqlServer(t *testing.T) {
sqlServerPass := gofakeit.Password(true, true, true, false, false, 10)
sqlServerDB := "master"
mssqlContainer, err := mssql.RunContainer(ctx,
testcontainers.WithImage("mcr.microsoft.com/azure-sql-edge"),
mssqlContainer, err := mssql.Run(ctx,
"mcr.microsoft.com/azure-sql-edge",
mssql.WithAcceptEULA(),
mssql.WithPassword(sqlServerPass),
)
@@ -61,7 +61,7 @@ func TestSqlServer(t *testing.T) {
want: result{pingOk: true, pingDeterminate: true},
},
{
input: "//server=badhost;user id=sa;database=master;password=",
input: fmt.Sprintf("//server=badhost;user id=sa;database=master;password=%s", sqlServerPass),
want: result{pingOk: false, pingDeterminate: false},
},
{
@@ -81,7 +81,8 @@ func TestSqlServer(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.input, func(t *testing.T) {
j, err := parseSqlServer(tt.input)
ctx := logContext.AddLogger(context.Background())
j, err := ParseSqlServer(ctx, tt.input)
if err != nil {
got := result{parseErr: true}
+36
View File
@@ -118,6 +118,42 @@ func TestParseSqlServerUserIgnoredBug2(t *testing.T) {
}
}
func TestParseSqlServerWithJdbcAndOdbcBridgeString(t *testing.T) {
subname := "//odbc:server=localhost;port=1433;database=testdb;password=testpassword"
wantHost := "localhost"
wantPort := "1433"
wantPassword := "testpassword"
wantDatabase := "testdb"
ctx := logContext.AddLogger(context.Background())
j, err := parseSqlServer(ctx, subname)
if err != nil {
t.Fatalf("parseSqlServer() error = %v", err)
}
if j == nil {
t.Fatalf("parseSqlServer() returned nil, expected valid connection.")
}
sqlServerConn, ok := j.(*SqlServerJDBC)
if !ok {
t.Fatalf("parseSqlServer() returned unexpected type %T, expected *SqlServerJDBC", j)
}
if sqlServerConn.Host != wantHost+":"+wantPort {
t.Errorf("Host mismatch. Got: %s, Want: %s", sqlServerConn.Host, wantHost+":"+wantPort)
}
if sqlServerConn.Password != wantPassword {
t.Errorf("Password mismatch. Got: %s, Want: %s", sqlServerConn.Password, wantPassword)
}
if sqlServerConn.Database != wantDatabase {
t.Errorf("Database mismatch. Got: %s, Want: %s", sqlServerConn.Database, wantDatabase)
}
}
func TestSQLServerHandler_ParseJDBCURL(t *testing.T) {
tests := []struct {
name string