Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions pkg/mssqldb/databases.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ func (c *Client) GrantPermissionOnDatabase(ctx context.Context, permission, db,

l.Debug("SQL QUERY", zap.String("q", command))

_, err := c.db.ExecContext(ctx, command, permission, db, user)
_, err := c.db.ExecContext(ctx, command)
if err != nil {
return err
}
Expand All @@ -144,13 +144,13 @@ func (c *Client) RevokePermissionOnDatabase(ctx context.Context, permission, db,
}

command := fmt.Sprintf(
"GRANT %s ON DATABASE::[%s] TO [%s];",
"REVOKE %s ON DATABASE::[%s] FROM [%s];",
fullPermission,
db,
user,
)

_, err := c.db.ExecContext(ctx, command, fullPermission, db, user)
_, err := c.db.ExecContext(ctx, command)
if err != 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.

🟡 Suggestion: The sibling GrantPermissionOnDatabase (line ~126) still passes inert positional args permission, db, user to ExecContext — the same pattern cleaned up here. Consider removing them there too for consistency.

Suggested change
if err != nil {
_, err := c.db.ExecContext(ctx, command)

return err
}
Expand Down
15 changes: 14 additions & 1 deletion pkg/mssqldb/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,14 @@ const (
func (c *Client) CreateLogin(ctx context.Context, loginType LoginType, username, password string) error {
l := ctxzap.Extract(ctx)

// Username is interpolated into bracket-quoted SQL Server identifiers
// below. Reject characters that would let the value break out of the
// brackets (this is the same guard the rest of this package uses on
// identifier-interpolated inputs).
if strings.ContainsAny(username, "[]\"';") {
return fmt.Errorf("invalid characters in username")
}

var query string
switch loginType {
case LoginTypeWindows:
Expand All @@ -399,7 +407,12 @@ func (c *Client) CreateLogin(ctx context.Context, loginType LoginType, username,
// For SQL Server authentication, only username and password are used
loginName := fmt.Sprintf("[%s]", username)
l.Debug("creating SQL login", zap.String("login", loginName))
query = fmt.Sprintf("CREATE LOGIN %s WITH PASSWORD = '%s';", loginName, password)
// SQL Server string literals escape ' by doubling it. Without this,
// a password containing ' breaks out of the literal -- a SQL
// injection vector and at minimum a syntax error for legitimate
// users whose passwords contain '.
escapedPassword := strings.ReplaceAll(password, "'", "''")
query = fmt.Sprintf("CREATE LOGIN %s WITH PASSWORD = '%s';", loginName, escapedPassword)
Comment on lines 408 to +415
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.

🟡 Suggestion: The password escaping is correct, but username is bracket-quoted via [%s] without escaping ] — a username containing ] can break out of the identifier quoting. Other functions in this file (lines 287, 334) validate inputs against []"'; before interpolation. Consider adding the same ContainsAny guard on username here, or escaping ]]] inside the brackets (SQL Server's bracket-identifier escape).

case LoginTypeAzureAD, LoginTypeEntraID:
// Azure AD and Entra ID use external provider
loginName := fmt.Sprintf("[%s]", username)
Expand Down
Loading