CVE-2024-27304: Insufficient Information (NVD-CWE-noinfo)
value: pgx is a PostgreSQL driver and toolkit for Go. SQL injection can occur if an attacker can cause a single query or bind message to exceed 4 GB in size. An integer overflow in the calculated message size can cause the one large message to be sent as multiple messages under the attacker's control. The problem is resolved in v4.18.2 and v5.5.4. As a workaround, reject user input large enough to cause a single query or bind message to exceed 4 GB in size.
CWE description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
Published: 2024-03-06T19:15Z
Repository: https://github.com/jackc/pgx
Language: Go
Files changed: internal/sanitize/sanitize.go, internal/sanitize/sanitize_test.go
Commit date: 2024-03-04 09:09:42 -0600
Commit message: SQL sanitizer wraps arguments in parentheses

pgx v5 was not vulnerable to CVE-2024-27289 do to how the sanitizer was
being called. But the sanitizer itself still had the underlying issue.
This commit ports the fix from pgx v4 to v5 to ensure that the issue
does not emerge if pgx uses the sanitizer differently in the future.

Diff: diff --git a/internal/sanitize/sanitize.go b/internal/sanitize/sanitize.go
index f9091cd4..08d24fe4 100644
--- a/internal/sanitize/sanitize.go
+++ b/internal/sanitize/sanitize.go
@@ -61,10 +61,14 @@ func (q *Query) Sanitize(args ...any) (string, error) {
 				str = arg.Truncate(time.Microsecond).Format("'2006-01-02 15:04:05.999999999Z07:00:00'")
 			default:
 				return "", fmt.Errorf("invalid arg type: %T", arg)
 			}
 			argUse[argIdx] = true
+
+			// Prevent SQL injection via Line Comment Creation
+			// https://github.com/jackc/pgx/security/advisories/GHSA-m7wr-2xf7-cm9p
+			str = "(" + str + ")"
 		default:
 			return "", fmt.Errorf("invalid Part type: %T", part)
 		}
 		buf.WriteString(str)
 	}
diff --git a/internal/sanitize/sanitize_test.go b/internal/sanitize/sanitize_test.go
index e2533aab..191bf1e9 100644
--- a/internal/sanitize/sanitize_test.go
+++ b/internal/sanitize/sanitize_test.go
@@ -130,51 +130,61 @@ func TestQuerySanitize(t *testing.T) {
 			expected: `select 42`,
 		},
 		{
 			query:    sanitize.Query{Parts: []sanitize.Part{"select ", 1}},
 			args:     []any{int64(42)},
-			expected: `select 42`,
+			expected: `select (42)`,
 		},
 		{
 			query:    sanitize.Query{Parts: []sanitize.Part{"select ", 1}},
 			args:     []any{float64(1.23)},
-			expected: `select 1.23`,
+			expected: `select (1.23)`,
 		},
 		{
 			query:    sanitize.Query{Parts: []sanitize.Part{"select ", 1}},
 			args:     []any{true},
-			expected: `select true`,
+			expected: `select (true)`,
 		},
 		{
 			query:    sanitize.Query{Parts: []sanitize.Part{"select ", 1}},
 			args:     []any{[]byte{0, 1, 2, 3, 255}},
-			expected: `select '\x00010203ff'`,
+			expected: `select ('\x00010203ff')`,
 		},
 		{
 			query:    sanitize.Query{Parts: []sanitize.Part{"select ", 1}},
 			args:     []any{nil},
-			expected: `select null`,
+			expected: `select (null)`,
 		},
 		{
 			query:    sanitize.Query{Parts: []sanitize.Part{"select ", 1}},
 			args:     []any{"foobar"},
-			expected: `select 'foobar'`,
+			expected: `select ('foobar')`,
 		},
 		{
 			query:    sanitize.Query{Parts: []sanitize.Part{"select ", 1}},
 			args:     []any{"foo'bar"},
-			expected: `select 'foo''bar'`,
+			expected: `select ('foo''bar')`,
 		},
 		{
 			query:    sanitize.Query{Parts: []sanitize.Part{"select ", 1}},
 			args:     []any{`foo\'bar`},
-			expected: `select 'foo\''bar'`,
+			expected: `select ('foo\''bar')`,
 		},
 		{
 			query:    sanitize.Query{Parts: []sanitize.Part{"insert ", 1}},
 			args:     []any{time.Date(2020, time.March, 1, 23, 59, 59, 999999999, time.UTC)},
-			expected: `insert '2020-03-01 23:59:59.999999Z'`,
+			expected: `insert ('2020-03-01 23:59:59.999999Z')`,
+		},
+		{
+			query:    sanitize.Query{Parts: []sanitize.Part{"select 1-", 1}},
+			args:     []any{int64(-1)},
+			expected: `select 1-(-1)`,
+		},
+		{
+			query:    sanitize.Query{Parts: []sanitize.Part{"select 1-", 1}},
+			args:     []any{float64(-1)},
+			expected: `select 1-(-1)`,
 		},
 	}
 
 	for i, tt := range successfulTests {
 		actual, err := tt.query.Sanitize(tt.args...)

Vulnerable code: 			expected: `select 42`,
			expected: `select 1.23`,
			expected: `select true`,
			expected: `select '\x00010203ff'`,
			expected: `select null`,
			expected: `select 'foobar'`,
			expected: `select 'foo''bar'`,
			expected: `select 'foo\''bar'`,
			expected: `insert '2020-03-01 23:59:59.999999Z'`,
Fixed code: 
			// Prevent SQL injection via Line Comment Creation
			// https://github.com/jackc/pgx/security/advisories/GHSA-m7wr-2xf7-cm9p
			str = "(" + str + ")"
			expected: `select (42)`,
			expected: `select (1.23)`,
			expected: `select (true)`,
			expected: `select ('\x00010203ff')`,
			expected: `select (null)`,
			expected: `select ('foobar')`,
			expected: `select ('foo''bar')`,
			expected: `select ('foo\''bar')`,
			expected: `insert ('2020-03-01 23:59:59.999999Z')`,
		},
		{
			query:    sanitize.Query{Parts: []sanitize.Part{"select 1-", 1}},
			args:     []any{int64(-1)},
			expected: `select 1-(-1)`,
		},
		{
			query:    sanitize.Query{Parts: []sanitize.Part{"select 1-", 1}},
			args:     []any{float64(-1)},
			expected: `select 1-(-1)`,