-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Prevent security exploit in SqlAzureDacpacDeploymentV1 and SqlDacpacDeploymentOnMachineGroupV0 where Invoke-Expression is used #21947
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 25 commits
Commits
Show all changes
45 commits
Select commit
Hold shift + click to select a range
6a6bcb6
Init work
rm-dmiri 220796c
Remove whitelist to avoid as list might be incomplete
rm-dmiri e60c1e0
Add some tests
rm-dmiri f9e2e77
Add Invoke-SqlCmdExe function and refactor SQL command execution for …
rm-dmiri da6cdbe
Reduce task version to 272 for SqlAzureDacpacDeploymentV1 and SqlDacp…
rm-dmiri 0048144
Bump version to 272.1 for SqlAzureDacpacDeploymentV1 and SqlDacpacDep…
rm-dmiri 67bcc2c
Merge branch 'master' into users/rm-dmiri/fix-sqldacpac-injection
rm-dmiri f6b6ed8
Merge branch 'master' into users/rm-dmiri/fix-sqldacpac-injection
rm-dmiri 70fffba
Merge branch 'master' into users/rm-dmiri/fix-sqldacpac-injection
rm-dmiri 6a7d1ff
Simplify approach and remove usage of regex; Enrich tests;
rm-dmiri 9e89fb1
Merge branch 'users/rm-dmiri/fix-sqldacpac-injection' of https://gith…
rm-dmiri 21f19d0
Merge branch 'master' into users/rm-dmiri/fix-sqldacpac-injection
rm-dmiri edaf27e
Fix PS 3/4 compat: replace ::new() with New-Object; remove last regex…
rm-dmiri 63be42d
Merge branch 'users/rm-dmiri/fix-sqldacpac-injection' of https://gith…
rm-dmiri a563e4c
Merge branch 'master' into users/rm-dmiri/fix-sqldacpac-injection
rm-dmiri 7e06ec1
Bump SqlAzureDacpacDeploymentV1 to v1.273.0 for sprint 273
rm-dmiri 98afd69
Bump SqlDacpacDeploymentOnMachineGroupV0 to v0.273.0 for sprint 273
rm-dmiri e49d076
Replace splatting with Sanitizer module for injection prevention
rm-dmiri 62fad2b
Remove unnecessary blank line in AzureFileCopy.ps1
rm-dmiri 392de7f
Implement SQL argument sanitization to prevent injection attacks in S…
rm-dmiri e18becb
Improvements
rm-dmiri 5301477
Return some comments from before
rm-dmiri ff10025
Merge branch 'master' into users/rm-dmiri/fix-sqldacpac-injection
rm-dmiri 09f8ed4
Delete some comments and use .Value instead .Text parser
rm-dmiri 6c1a4df
Cmd placeholder in parser call
rm-dmiri 0260662
Add improvements
rm-dmiri 3611209
Fixing pr comments first part
rm-dmiri bbfe1d0
Addressing Pr comments and refactoring part 2
rm-dmiri 5e09e2d
Code polishing
rm-dmiri 73178e1
Unit tests update and comments update
rm-dmiri 8cf4ce9
Merge branch 'master' into users/rm-dmiri/fix-sqldacpac-injection
rm-dmiri 0934903
More updates in logic and enhanced tests
rm-dmiri 4705d31
Refactor SQL argument handling and improve safety in Invoke-SqlScript…
rm-dmiri dfe78e3
Merge branch 'master' into users/rm-dmiri/fix-sqldacpac-injection
rm-dmiri 45d4ac2
Merge branch 'master' into users/rm-dmiri/fix-sqldacpac-injection
rm-dmiri 873e762
Bump task versions
rm-dmiri 7a18632
Merge branch 'users/rm-dmiri/fix-sqldacpac-injection' of https://gith…
rm-dmiri 3cb67be
Address uncovered paths in OnMachineGroup task and deduplicate some code
rm-dmiri a107024
Small fixes and Pr comment improvement
rm-dmiri 6109e4e
Address PR comments
rm-dmiri 5b8df4a
Merge branch 'master' into users/rm-dmiri/fix-sqldacpac-injection
rm-dmiri 9a1c52d
Merge branch 'master' into users/rm-dmiri/fix-sqldacpac-injection
rm-dmiri 16e9936
Remove misleading usage of $args
rm-dmiri 546ebbb
Additional fixes
rm-dmiri 04fa3e8
Prevent injection by blocking reserved parameters in Merge-Additional…
rm-dmiri File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
129 changes: 129 additions & 0 deletions
129
Tasks/SqlAzureDacpacDeploymentV1/Tests/L0SecurityFunctions.ps1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,129 @@ | ||
| # Unit tests for SQL argument sanitization security functions | ||
| [CmdletBinding()] | ||
|
nemanjarogic marked this conversation as resolved.
|
||
| param() | ||
|
|
||
| # Import test helpers | ||
| . $PSScriptRoot\MockVariable.ps1 | ||
|
|
||
| # Import the functions under test | ||
| . $PSScriptRoot\..\Utility.ps1 | ||
|
|
||
| Describe "Execute-Command Security Tests" { | ||
| Context "AST Parser Validation" { | ||
| It "Should use token .Value instead of .Text" { | ||
| # This test verifies the fix for Ivan's concern about quote handling | ||
|
rm-dmiri marked this conversation as resolved.
Outdated
|
||
| # We check that the code uses $_.Value which removes quotes, | ||
| # rather than $_.Text which keeps them (causing double-quoting) | ||
|
|
||
| $utilityContent = Get-Content "$PSScriptRoot\..\Utility.ps1" -Raw | ||
| $utilityContent -match 'ForEach-Object\s*\{\s*\$_\.Value\s*\}' | Should Be $true | ||
| $utilityContent -match 'ForEach-Object\s*\{\s*\$_\.Text\s*\}' | Should Be $false | ||
| } | ||
|
|
||
| It "Should validate parse errors before execution" { | ||
| $utilityContent = Get-Content "$PSScriptRoot\..\Utility.ps1" -Raw | ||
| # Should check parseErrors and throw if any exist | ||
| $utilityContent -match 'if\s*\(\s*\$parseErrors' | Should Be $true | ||
| $utilityContent -match 'throw.*Invalid sqlpackage argument' | Should Be $true | ||
| } | ||
|
|
||
| It "Should use array-based argument passing, not Invoke-Expression" { | ||
| $utilityContent = Get-Content "$PSScriptRoot\..\Utility.ps1" -Raw | ||
| # Should NOT use Invoke-Expression in Execute-Command | ||
| $executeCommandSection = $utilityContent -split 'function Execute-Command' | ||
| if ($executeCommandSection.Count -gt 1) { | ||
| $functionBody = $executeCommandSection[1] -split 'function ', 2 | Select-Object -First 1 | ||
| $functionBody -match 'Invoke-Expression' | Should Be $false | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| Describe "Should-UseSanitizedArguments Dual-Gating Tests" { | ||
| Context "Backward Compatibility" { | ||
| It "Should fail-open when VstsTaskSdk unavailable" { | ||
| # When Get-VstsPipelineFeature cmdlet doesn't exist, | ||
| # should return false (backward compatibility) | ||
| $utilityContent = Get-Content "$PSScriptRoot\..\Utility.ps1" -Raw | ||
| $utilityContent -match 'Get-Command.*Get-VstsPipelineFeature.*SilentlyContinue' | Should Be $true | ||
| } | ||
| } | ||
| } | ||
|
|
||
| Describe "Get-SanitizedSqlArguments Security Tests" { | ||
| Context "Fail-Closed Behavior" { | ||
| It "Should validate sanitizer returns an array" { | ||
| $utilityContent = Get-Content "$PSScriptRoot\..\Utility.ps1" -Raw | ||
| # Should check that result is an array type | ||
| $utilityContent -match '\$sanitizedArray -isnot \[Array\]' | Should Be $true | ||
| $utilityContent -match 'throw.*unexpected type' | Should Be $true | ||
| } | ||
|
|
||
| It "Should detect empty array (all input blocked)" { | ||
| $utilityContent = Get-Content "$PSScriptRoot\..\Utility.ps1" -Raw | ||
| # Should check for empty array | ||
| $utilityContent -match '\$sanitizedArray\.Count -eq 0' | Should Be $true | ||
| $utilityContent -match 'throw.*empty array.*blocked' | Should Be $true | ||
| } | ||
|
|
||
| It "Should throw on sanitizer failure" { | ||
| $utilityContent = Get-Content "$PSScriptRoot\..\Utility.ps1" -Raw | ||
| # Should have try-catch that throws on error | ||
| $getSanitizedSection = $utilityContent -split 'function Get-SanitizedSqlArguments' | ||
| if ($getSanitizedSection.Count -gt 1) { | ||
| $functionBody = $getSanitizedSection[1] -split 'function ', 2 | Select-Object -First 1 | ||
| $functionBody -match 'catch\s*\{' | Should Be $true | ||
| $functionBody -match 'SECURITY ERROR.*Failed to sanitize' | Should Be $true | ||
| $functionBody -match 'throw\s*\$errorMessage' | Should Be $true | ||
| } | ||
| } | ||
| } | ||
|
|
||
| Context "Telemetry" { | ||
| It "Should emit telemetry when sanitization modifies input" { | ||
| $utilityContent = Get-Content "$PSScriptRoot\..\Utility.ps1" -Raw | ||
| $utilityContent -match 'if\s*\(\s*\$sanitizedString -ne \$InputArgs\s*\)' | Should Be $true | ||
| $utilityContent -match 'telemetry\.publish.*SqlArgumentSanitization' | Should Be $true | ||
| } | ||
| } | ||
| } | ||
|
|
||
| Describe "Publish-FeatureFlagCheckTelemetry Tests" { | ||
| Context "Telemetry Format" { | ||
| It "Should emit telemetry with correct area and feature" { | ||
| $utilityContent = Get-Content "$PSScriptRoot\..\Utility.ps1" -Raw | ||
| $utilityContent -match 'telemetry\.publish area=TaskHub;feature=SqlArgumentSanitizationCheck' | Should Be $true | ||
| } | ||
|
|
||
| It "Should include checkType in telemetry data" { | ||
| $utilityContent = Get-Content "$PSScriptRoot\..\Utility.ps1" -Raw | ||
| # Function should accept CheckType parameter and include in data | ||
| $telemetrySection = $utilityContent -split 'function Publish-FeatureFlagCheckTelemetry' | ||
| if ($telemetrySection.Count -gt 1) { | ||
| $functionBody = $telemetrySection[1] -split 'function ', 2 | Select-Object -First 1 | ||
| $functionBody -match 'checkType\s*=' | Should Be $true | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| Describe "Comment Restoration Tests" { | ||
| Context "Original Comments" { | ||
| It "Should have 'Initialize Rest API Helpers' comment in DeploySqlAzure.ps1" { | ||
| $deployContent = Get-Content "$PSScriptRoot\..\DeploySqlAzure.ps1" -Raw | ||
| $deployContent -match '# Initialize Rest API Helpers' | Should Be $true | ||
| } | ||
|
|
||
| It "Should have 'Import the loc strings' comment in DeploySqlAzure.ps1" { | ||
| $deployContent = Get-Content "$PSScriptRoot\..\DeploySqlAzure.ps1" -Raw | ||
| $deployContent -match '# Import the loc strings' | Should Be $true | ||
| } | ||
|
|
||
| It "Should have function comment in Utility.ps1" { | ||
| $utilityContent = Get-Content "$PSScriptRoot\..\Utility.ps1" -Raw | ||
| $utilityContent -match '# Function to import SqlPS module' | Should Be $true | ||
| } | ||
| } | ||
| } | ||
|
|
||
| Write-Host "Security function tests completed" | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.