private VariableState VisitAssignment(AssignmentExpressionSyntax node, ExecutionState state) { var symbol = state.GetSymbol(node.Left); MethodBehavior behavior = behaviorRepo.GetMethodBehavior(symbol); var variableState = VisitExpression(node.Right, state); //Additionnal analysis by extension foreach (var ext in extensions) { ext.VisitAssignment(node, state, behavior, symbol, variableState); } IdentifierNameSyntax parentIdentifierSyntax = GetParentIdentifier(node.Left); if (parentIdentifierSyntax != null) { state.MergeValue(ResolveIdentifier(parentIdentifierSyntax.Identifier), variableState); } if (behavior != null && //Injection behavior.isInjectableField && variableState.taint != VariableTaint.CONSTANT && //Skip safe values variableState.taint != VariableTaint.SAFE) { var newRule = LocaleUtil.GetDescriptor(behavior.localeInjection); var diagnostic = Diagnostic.Create(newRule, node.GetLocation()); state.AnalysisContext.ReportDiagnostic(diagnostic); } if (behavior != null && //Known Password API behavior.isPasswordField && variableState.taint == VariableTaint.CONSTANT //Only constant ) { var newRule = LocaleUtil.GetDescriptor(behavior.localePassword); var diagnostic = Diagnostic.Create(newRule, node.GetLocation()); state.AnalysisContext.ReportDiagnostic(diagnostic); } //TODO: tainted the variable being assign. return(variableState); }
private VariableState VisitAssignment(AssignmentExpressionSyntax node, ExecutionState state) { var leftSymbol = state.GetSymbol(node.Left); MethodBehavior behavior = null; if (leftSymbol != null) { behavior = leftSymbol.GetMethodBehavior(ProjectConfiguration.Behavior); } var variableState = VisitExpression(node.Right, state); //Additional analysis by extension foreach (var ext in Extensions) { ext.VisitAssignment(node, state, behavior, leftSymbol, variableState); } //if (leftSymbol != null) //{ // var rightTypeSymbol = state.AnalysisContext.SemanticModel.GetTypeInfo(node.Right).Type; // if (rightTypeSymbol == null) // return new VariableState(node.Right, VariableTaint.Unknown); // var leftTypeSymbol = state.AnalysisContext.SemanticModel.GetTypeInfo(node.Left).Type; // if (!state.AnalysisContext.SemanticModel.Compilation.ClassifyConversion(rightTypeSymbol, leftTypeSymbol).IsImplicit) // return new VariableState(node.Right, VariableTaint.Unknown); //} if (variableState.Taint != VariableTaint.Constant && behavior != null && // compare if all required sanitization bits are set ((ulong)(variableState.Taint & VariableTaint.Safe) & behavior.InjectableField.RequiredTaintBits) != behavior.InjectableField.RequiredTaintBits && (variableState.Taint & (ProjectConfiguration.AuditMode ? VariableTaint.Tainted | VariableTaint.Unknown : VariableTaint.Tainted)) != 0) { var newRule = LocaleUtil.GetDescriptor(behavior.InjectableField.Locale, "title_assignment"); var diagnostic = Diagnostic.Create(newRule, node.GetLocation()); state.AnalysisContext.ReportDiagnostic(diagnostic); } //TODO: taint the variable being assigned. return(variableState); }
private VariableState VisitAssignment(AssignmentExpressionSyntax node, ExecutionState state) { var symbol = state.GetSymbol(node.Left); MethodBehavior behavior = behaviorRepo.GetInjectableMethodBehavior(symbol); var variableState = VisitExpression(node.Right, state); if (node.Left is IdentifierNameSyntax) { var assignmentIdentifier = node.Left as IdentifierNameSyntax; state.UpdateValue(ResolveIdentifier(assignmentIdentifier.Identifier), variableState); } if (behavior != null && //If the API is at risk variableState.taint != VariableTaint.CONSTANT && //Skip safe values variableState.taint != VariableTaint.SAFE) { var newRule = LocaleUtil.GetDescriptor(behavior.vulnerabilityLocale); var diagnostic = Diagnostic.Create(newRule, node.GetLocation()); state.AnalysisContext.ReportDiagnostic(diagnostic); } return(variableState); }
private VariableState VisitInvocationAndCreation(ExpressionSyntax node, ArgumentListSyntax argList, ExecutionState state) { var symbol = state.GetSymbol(node); MethodBehavior behavior = behaviorRepo.GetMethodBehavior(symbol); int i = 0; if (argList == null) { return(new VariableState(node, VariableTaint.UNKNOWN)); } var returnState = new VariableState(node, VariableTaint.SAFE); foreach (var argument in argList.Arguments) { var argumentState = VisitExpression(argument.GetExpression(), state); if (symbol != null) { SGLogging.Log(symbol.ContainingType + "." + symbol.Name + " -> " + argumentState); } if (behavior != null) { //If the API is at risk if ((argumentState.taint == VariableTaint.TAINTED || //Tainted values argumentState.taint == VariableTaint.UNKNOWN) && Array.Exists(behavior.injectablesArguments, element => element == i) //If the current parameter can be injected. ) { var newRule = LocaleUtil.GetDescriptor(behavior.localeInjection); var diagnostic = Diagnostic.Create(newRule, node.GetLocation()); state.AnalysisContext.ReportDiagnostic(diagnostic); } else if (argumentState.taint == VariableTaint.CONSTANT && //Hard coded value Array.Exists(behavior.passwordArguments, element => element == i) //If the current parameter is a password ) { var newRule = LocaleUtil.GetDescriptor(behavior.localePassword); var diagnostic = Diagnostic.Create(newRule, node.GetLocation()); state.AnalysisContext.ReportDiagnostic(diagnostic); } else if ( // Array.Exists(behavior.taintFromArguments, element => element == i)) { returnState = returnState.merge(argumentState); } } //TODO: tainted all object passed in argument i++; } //Additionnal analysis by extension foreach (var ext in extensions) { ext.VisitInvocationAndCreation(node, argList, state); } var hasTaintFromArguments = behavior?.taintFromArguments?.Length > 0; if (hasTaintFromArguments) { return(returnState); } else { return(new VariableState(node, VariableTaint.UNKNOWN)); } }
private VariableState VisitAssignment(AssignmentExpressionSyntax node, ExecutionState state) { var leftSymbol = state.GetSymbol(node.Left); MethodBehavior behavior = null; if (leftSymbol != null) { behavior = leftSymbol.GetMethodBehavior(state.AnalysisContext.Options.AdditionalFiles); } var variableState = VisitExpression(node.Right, state); //Additional analysis by extension foreach (var ext in Extensions) { ext.VisitAssignment(node, state, behavior, leftSymbol, variableState); } if (leftSymbol != null) { var rightTypeSymbol = state.AnalysisContext.SemanticModel.GetTypeInfo(node.Right).Type; if (rightTypeSymbol == null) { return(new VariableState(node.Right, VariableTaint.Unknown)); } var leftTypeSymbol = state.AnalysisContext.SemanticModel.GetTypeInfo(node.Left).Type; if (!state.AnalysisContext.SemanticModel.Compilation.ClassifyConversion(rightTypeSymbol, leftTypeSymbol).IsImplicit) { return(new VariableState(node.Right, VariableTaint.Unknown)); } } IdentifierNameSyntax parentIdentifierSyntax = GetParentIdentifier(node.Left); if (parentIdentifierSyntax != null) { state.MergeValue(ResolveIdentifier(parentIdentifierSyntax.Identifier), variableState); } if (behavior != null && //Injection behavior.IsInjectableField && variableState.Taint != VariableTaint.Constant && //Skip safe values variableState.Taint != VariableTaint.Safe) { var newRule = LocaleUtil.GetDescriptor(behavior.LocaleInjection, "title_assignment"); var diagnostic = Diagnostic.Create(newRule, node.GetLocation()); state.AnalysisContext.ReportDiagnostic(diagnostic); } if (behavior != null && //Known Password API behavior.IsPasswordField && variableState.Taint == VariableTaint.Constant) //Only constant { var newRule = LocaleUtil.GetDescriptor(behavior.LocalePassword, "title_assignment"); var diagnostic = Diagnostic.Create(newRule, node.GetLocation()); state.AnalysisContext.ReportDiagnostic(diagnostic); } //TODO: taint the variable being assigned. return(variableState); }
/// <summary> /// Logic for each method invocation (including constructor) /// The argument list is required because <code>InvocationExpressionSyntax</code> and /// <code>ObjectCreationExpressionSyntax</code> do not share a common interface. /// </summary> /// <param name="node"></param> /// <param name="argList"></param> /// <param name="state"></param> /// <returns></returns> private VariableState VisitInvocationAndCreation(ExpressionSyntax node, ArgumentListSyntax argList, ExecutionState state, VariableState?initialVariableState = null) { var symbol = state.GetSymbol(node); if (symbol == null) { return(new VariableState(node, VariableTaint.Unknown)); } var behavior = symbol.GetMethodBehavior(state.AnalysisContext.Options.AdditionalFiles); var returnState = initialVariableState.HasValue && !symbol.IsStatic ? initialVariableState.Value : new VariableState(node, behavior?.TaintFromArguments?.Any() == true ? VariableTaint.Safe : VariableTaint.Unknown); for (var i = 0; i < argList?.Arguments.Count; i++) { var argument = argList.Arguments[i]; var argumentState = VisitExpression(argument.Expression, state); Logger.Log(symbol.ContainingType + "." + symbol.Name + " -> " + argumentState); if (behavior == null) { continue; } //If the API is at risk if ((argumentState.Taint == VariableTaint.Tainted || argumentState.Taint == VariableTaint.Unknown) && //Tainted values //If the current parameter can be injected. Array.Exists(behavior.InjectablesArguments, element => element == i)) { var newRule = LocaleUtil.GetDescriptor(behavior.LocaleInjection); var diagnostic = Diagnostic.Create(newRule, node.GetLocation(), GetMethodName(node), (i + 1).ToNthString()); state.AnalysisContext.ReportDiagnostic(diagnostic); } else if (argumentState.Taint == VariableTaint.Constant && //Hard coded value //If the current parameter is a password Array.Exists(behavior.PasswordArguments, element => element == i)) { var newRule = LocaleUtil.GetDescriptor(behavior.LocalePassword); var diagnostic = Diagnostic.Create(newRule, node.GetLocation(), GetMethodName(node), (i + 1).ToNthString()); state.AnalysisContext.ReportDiagnostic(diagnostic); } else if (Array.Exists(behavior.TaintFromArguments, element => element == i)) { returnState = returnState.Merge(argumentState); } //TODO: taint all objects passed as arguments //if (argument.Expression is IdentifierNameSyntax identifierNameSyntax) //{ // var argumentType = state.AnalysisContext.SemanticModel.GetTypeInfo(argument.Expression).Type; // if (argumentType.IsReferenceType && // argumentType.IsType("System.String")) // string is immutable // { // state.MergeValue(ResolveIdentifier(identifierNameSyntax.Identifier), // argumentState.Merge(new VariableState(argument, VariableTaint.Unknown))); // } //} } //Additional analysis by extension foreach (var ext in Extensions) { ext.VisitInvocationAndCreation(node, argList, state); } return(returnState); }
public void LoadConfiguration(string configurationFile) { var assembly = typeof(MethodBehaviorRepository).GetTypeInfo().Assembly; using (Stream stream = assembly.GetManifestResourceStream("RoslynSecurityGuard.Config." + configurationFile)) using (StreamReader reader = new StreamReader(stream)) { var yaml = new YamlStream(); yaml.Load(reader); var mapping = (YamlMappingNode)yaml.Documents[0].RootNode; foreach (var entry in mapping.Children) { var key = (YamlScalarNode)entry.Key; var value = (YamlMappingNode)entry.Value; //The behavior structure allows the configuration of injectable arguments and password field //This is the reason. The format merges the two concepts. //Loading the properties for each entry string beNamespace = GetField(entry, "namespace", true); string beClassName = GetField(entry, "className", true); string beMember = GetField(entry, "member", true); string beName = GetField(entry, "name", true); //--Method behavior string beInjectableArguments = GetField(entry, "injectableArguments", defaultValue: ""); string bePasswordArguments = GetField(entry, "passwordArguments", defaultValue: ""); string beArgTypes = GetField(entry, "argTypes"); //--Field behavior bool beInjectableField = bool.Parse(GetField(entry, "injectableField", defaultValue: "false")); bool bePasswordField = bool.Parse(GetField(entry, "passwordField", defaultValue: "false")); //--Localisation string beLocale = GetField(entry, "locale"); string beLocalePass = GetField(entry, "localePass"); string beTaintFromArguments = GetField(entry, "taintFromArguments", defaultValue: ""); //Converting the list of index to array int[] argumentsIndexes = convertToIntArray(beInjectableArguments.Split(',')); int[] passwordIndexes = convertToIntArray(bePasswordArguments.Split(',')); int[] taintFromArgumentsIndexes = convertToIntArray(beTaintFromArguments.Split(',')); foreach (var locale in new string[] { beLocale, beLocalePass }) { if (locale != null && !descriptors.ContainsKey(locale)) { descriptors.Add(locale, LocaleUtil.GetDescriptor(locale)); } } //Validate that 'argumentsIndexes' field if ((!beInjectableField && !bePasswordField) && //Not a field signatures, arguments indexes is expected. argumentsIndexes.Length == 0 && passwordIndexes.Length == 0 && taintFromArgumentsIndexes.Length == 0) { throw new Exception("The method behavior " + key + " is not missing injectableArguments or passwordArguments property"); } //Injection based vulnerability string globalKey = beArgTypes != null ? // (beNamespace + "." + beClassName + "|" + beName + "|" + beArgTypes) : //With arguments types discriminator (beNamespace + "." + beClassName + "|" + beName); //Minimalist configuration methodInjectableArguments.Add(globalKey, new MethodBehavior(argumentsIndexes, passwordIndexes, taintFromArgumentsIndexes, beLocale, beLocalePass, beInjectableField, bePasswordField)); //SGLogging.Log(beNamespace); } //SGLogging.Log(methodInjectableArguments.Count + " signatures loaded."); } }
public void LoadConfiguration(string configurationFile) { var assembly = typeof(MethodBehaviorRepository).GetTypeInfo().Assembly; using (Stream stream = assembly.GetManifestResourceStream("RoslynSecurityGuard." + configurationFile)) using (StreamReader reader = new StreamReader(stream)) { var yaml = new YamlStream(); yaml.Load(reader); var mapping = (YamlMappingNode)yaml.Documents[0].RootNode; foreach (var entry in mapping.Children) { var key = (YamlScalarNode)entry.Key; var value = (YamlMappingNode)entry.Value; //Loading the properties for each entry string beNamespace = ((YamlScalarNode)value.Children[new YamlScalarNode("namespace")]).Value; string beClassName = ((YamlScalarNode)value.Children[new YamlScalarNode("className")]).Value; string beMember = ((YamlScalarNode)value.Children[new YamlScalarNode("member")]).Value; string beName = ((YamlScalarNode)value.Children[new YamlScalarNode("name")]).Value; string beInjectableArguments = ""; try { beInjectableArguments = ((YamlScalarNode)value.Children[new YamlScalarNode("injectableArguments")]).Value; } catch (KeyNotFoundException) { } string bePasswordArguments = ""; try { bePasswordArguments = ((YamlScalarNode)value.Children[new YamlScalarNode("passwordArguments")]).Value; } catch (KeyNotFoundException) { } string beArgTypes = null; try { beArgTypes = ((YamlScalarNode)value.Children[new YamlScalarNode("argTypes")]).Value.Trim(); } catch (KeyNotFoundException) { } string beLocale = ((YamlScalarNode)value.Children[new YamlScalarNode("locale")]).Value; //Converting the list of index to array int[] argumentsIndexes = convertToIntArray(beInjectableArguments.Split(',')); int[] passwordIndexes = convertToIntArray(bePasswordArguments.Split(',')); if (!descriptors.ContainsKey(beLocale)) { var newDescriptor = LocaleUtil.GetDescriptor(beLocale); descriptors.Add(beLocale, newDescriptor); } if (argumentsIndexes.Length == 0 && passwordIndexes.Length == 0) { throw new Exception("The method behavior " + key + " is not missing injectableArguments or passwordArguments property"); } //Injection based vulnerability if (beArgTypes != null) { methodInjectableArguments.Add(beNamespace + "." + beClassName + "|" + beName + "|" + beArgTypes, new MethodBehavior(argumentsIndexes, passwordIndexes, beLocale)); } else { methodInjectableArguments.Add(beNamespace + "." + beClassName + "|" + beName, new MethodBehavior(argumentsIndexes, passwordIndexes, beLocale)); } //SGLogging.Log(beNamespace); } //SGLogging.Log(methodInjectableArguments.Count + " signatures loaded."); } }
/// <summary> /// Logic for each method invocation (including constructor) /// The argument list is required because <code>InvocationExpressionSyntax</code> and /// <code>ObjectCreationExpressionSyntax</code> do not share a common interface. /// </summary> private VariableState VisitInvocationAndCreation(ExpressionSyntax node, ArgumentListSyntax argList, ExecutionState state, VariableTaint?initialTaint = null, VariableState memberVariableState = null) { var symbol = state.GetSymbol(node); if (symbol == null) { return(new VariableState(node, initialTaint ?? VariableTaint.Unknown)); } var methodSymbol = symbol as IMethodSymbol; bool isExtensionMethod = methodSymbol?.ReducedFrom != null; var behavior = symbol.GetMethodBehavior(ProjectConfiguration.Behavior); IReadOnlyDictionary <int, PostCondition> postConditions = null; if (behavior != null) { postConditions = GetPostConditions(behavior, isExtensionMethod, argList, state); } PostCondition returnPostCondition = null; postConditions?.TryGetValue(-1, out returnPostCondition); VariableState returnState = initialTaint != null && !symbol.IsStatic ? new VariableState(node, initialTaint.Value) : new VariableState(node, argList?.Arguments.Count > 0 && behavior != null ? VariableTaint.Unset : VariableTaint.Unknown); var argCount = argList?.Arguments.Count; var argumentStates = argCount.HasValue && argCount.Value > 0 && (postConditions?.Any(c => c.Key != -1 && (c.Value.Taint != 0ul || c.Value.TaintFromArguments.Any())) == true || methodSymbol != null && methodSymbol.Parameters.Any(x => x.RefKind != RefKind.None)) ? new VariableState[argCount.Value] : null; for (var i = 0; i < argList?.Arguments.Count; i++) { var argument = argList.Arguments[i]; var argumentState = VisitExpression(argument.GetExpression(), state); if (argumentStates != null) { argumentStates[i] = argumentState; } #if DEBUG Logger.Log(symbol.ContainingType + "." + symbol.Name + " -> " + argumentState); #endif var adjustedArgumentIdx = isExtensionMethod ? i + 1 : i; if (behavior != null) { if ((argumentState.Taint & (ProjectConfiguration.AuditMode ? VariableTaint.Tainted | VariableTaint.Unknown : VariableTaint.Tainted)) != 0) { //If the current parameter can be injected. if (behavior.InjectableArguments.TryGetValue(adjustedArgumentIdx, out var injectableArgument) && (injectableArgument.RequiredTaintBits & (ulong)argumentState.Taint) != injectableArgument.RequiredTaintBits) { var newRule = LocaleUtil.GetDescriptor(injectableArgument.Locale); var diagnostic = Diagnostic.Create(newRule, argument.GetExpression().GetLocation(), GetMethodName(node), (i + 1).ToNthString()); state.AnalysisContext.ReportDiagnostic(diagnostic); } } else if (argumentState.Taint == VariableTaint.Constant) { if (behavior.InjectableArguments.TryGetValue(adjustedArgumentIdx, out var injectableArgument) && injectableArgument.Not && (injectableArgument.RequiredTaintBits & (ulong)argumentState.Taint) != 0ul) { var newRule = LocaleUtil.GetDescriptor(injectableArgument.Locale); var diagnostic = Diagnostic.Create(newRule, argument.GetExpression().GetLocation(), GetMethodName(node), (i + 1).ToNthString()); state.AnalysisContext.ReportDiagnostic(diagnostic); } } } var argumentToSearch = adjustedArgumentIdx; if (methodSymbol != null && i >= methodSymbol.Parameters.Length && methodSymbol.Parameters[methodSymbol.Parameters.Length - 1].IsParams) { argumentToSearch = isExtensionMethod ? methodSymbol.Parameters.Length : methodSymbol.Parameters.Length - 1; } if (returnPostCondition == null || returnPostCondition.TaintFromArguments.Contains(argumentToSearch)) { returnState.MergeTaint(argumentState.Taint); } //TODO: taint all objects passed as arguments } if (returnPostCondition != null) { returnState.ApplyTaint(returnPostCondition.Taint); } if (argumentStates != null) { for (var i = 0; i < argList.Arguments.Count; i++) { var adjustedPostConditionIdx = isExtensionMethod ? i + 1 : i; if (postConditions != null && postConditions.TryGetValue(adjustedPostConditionIdx, out var postCondition)) { foreach (var argIdx in postCondition.TaintFromArguments) { var adjustedArgumentIdx = isExtensionMethod ? argIdx + 1 : argIdx; argumentStates[adjustedPostConditionIdx].MergeTaint(argumentStates[adjustedArgumentIdx].Taint); } argumentStates[adjustedPostConditionIdx].ApplyTaint(postCondition.Taint); } else if (methodSymbol != null) { if (i >= methodSymbol.Parameters.Length) { if (!methodSymbol.Parameters[methodSymbol.Parameters.Length - 1].IsParams) { throw new IndexOutOfRangeException(); } } else if (methodSymbol.Parameters[i].RefKind != RefKind.None) { argumentStates[i].MergeTaint(returnState.Taint); } } } } if (memberVariableState != null && methodSymbol != null && methodSymbol.ReturnsVoid && !methodSymbol.IsStatic && methodSymbol.Parameters.All(x => x.RefKind == RefKind.None)) { memberVariableState.MergeTaint(returnState.Taint); } //Additional analysis by extension foreach (var ext in Extensions) { ext.VisitInvocationAndCreation(node, argList, state); } return(returnState); }
/// <summary> /// Logic for each method invocation (including constructor) /// The argument list is required because <code>InvocationExpressionSyntax</code> and /// <code>ObjectCreationExpressionSyntax</code> do not share a common interface. /// </summary> /// <param name="node"></param> /// <param name="argList"></param> /// <param name="state"></param> /// <returns></returns> private VariableState VisitInvocationAndCreation(ExpressionSyntax node, ArgumentListSyntax argList, ExecutionState state) { var symbol = state.GetSymbol(node); MethodBehavior behavior = BehaviorRepo.GetMethodBehavior(symbol); int i = 0; if (argList == null) { return(new VariableState(node, VariableTaint.Unknown)); } var returnState = new VariableState(node, VariableTaint.Safe); foreach (var argument in argList.Arguments) { var argumentState = VisitExpression(argument.Expression, state); if (symbol != null) { Logger.Log(symbol.ContainingType + "." + symbol.Name + " -> " + argumentState); } if (behavior != null) { //If the API is at risk if ((argumentState.Taint == VariableTaint.Tainted || argumentState.Taint == VariableTaint.Unknown) && //Tainted values //If the current parameter can be injected. Array.Exists(behavior.InjectablesArguments, element => element == i)) { var newRule = LocaleUtil.GetDescriptor(behavior.LocaleInjection); var diagnostic = Diagnostic.Create(newRule, node.GetLocation()); state.AnalysisContext.ReportDiagnostic(diagnostic); } else if (argumentState.Taint == VariableTaint.Constant && //Hard coded value //If the current parameter is a password Array.Exists(behavior.PasswordArguments, element => element == i)) { var newRule = LocaleUtil.GetDescriptor(behavior.LocalePassword); var diagnostic = Diagnostic.Create(newRule, node.GetLocation()); state.AnalysisContext.ReportDiagnostic(diagnostic); } else if (Array.Exists(behavior.TaintFromArguments, element => element == i)) { returnState = returnState.Merge(argumentState); } } //TODO: tainted all object passed in argument i++; } //Additional analysis by extension foreach (var ext in Extensions) { ext.VisitInvocationAndCreation(node, argList, state); } var hasTaintFromArguments = behavior?.TaintFromArguments?.Length > 0; return(hasTaintFromArguments ? returnState : new VariableState(node, VariableTaint.Unknown)); }
public void LoadDiagnosticLocale() { DiagnosticDescriptor desc = LocaleUtil.GetDescriptor("SCS0001"); Console.WriteLine("Description: " + desc.Description); }
/// <summary> /// Logic for each method invocation (including constructor) /// The argument list is required because <code>InvocationExpressionSyntax</code> and /// <code>ObjectCreationExpressionSyntax</code> do not share a common interface. /// </summary> /// <param name="node"></param> /// <param name="argList"></param> /// <param name="state"></param> /// <returns></returns> private VariableState VisitInvocationAndCreation(ExpressionSyntax node, ArgumentListSyntax argList, ExecutionState state, VariableState initialVariableState = null) { var symbol = state.GetSymbol(node); if (symbol == null) { return(new VariableState(node, VariableTaint.Unknown)); } VariableState returnState; var behavior = symbol.GetMethodBehavior(state.AnalysisContext.Options.AdditionalFiles); if (behavior?.TaintFromArguments.Length == 1 && behavior.TaintFromArguments[0] == -1) { returnState = new VariableState(node, VariableTaint.Safe); } else { returnState = initialVariableState != null && !symbol.IsStatic ? initialVariableState : new VariableState(node, behavior?.TaintFromArguments?.Any() == true ? VariableTaint.Safe : VariableTaint.Unknown); } bool isExtensionMethod = (symbol as IMethodSymbol)?.ReducedFrom != null; for (var i = 0; i < argList?.Arguments.Count; i++) { var argument = argList.Arguments[i]; var argumentState = VisitExpression(argument.GetExpression(), state); Logger.Log(symbol.ContainingType + "." + symbol.Name + " -> " + argumentState); if (behavior == null) { continue; } //If the API is at risk if ((argumentState.Taint == VariableTaint.Tainted || argumentState.Taint == VariableTaint.Unknown) && //Tainted values //If the current parameter can be injected. Array.Exists(behavior.InjectablesArguments, element => element == (isExtensionMethod ? i + 1 : i))) { var newRule = LocaleUtil.GetDescriptor(behavior.LocaleInjection); var diagnostic = Diagnostic.Create(newRule, node.GetLocation(), GetMethodName(node), (i + 1).ToNthString()); state.AnalysisContext.ReportDiagnostic(diagnostic); } else if (argumentState.Taint == VariableTaint.Constant && //Hard coded value //If the current parameter is a password Array.Exists(behavior.PasswordArguments, element => element == (isExtensionMethod ? i + 1 : i))) { var newRule = LocaleUtil.GetDescriptor(behavior.LocalePassword); var diagnostic = Diagnostic.Create(newRule, node.GetLocation(), GetMethodName(node), (i + 1).ToNthString()); state.AnalysisContext.ReportDiagnostic(diagnostic); } else if (Array.Exists(behavior.TaintFromArguments, element => element == (isExtensionMethod ? i + 1 : i))) { returnState.Merge(argumentState); } //TODO: taint all objects passed as arguments } //Additional analysis by extension foreach (var ext in Extensions) { ext.VisitInvocationAndCreation(node, argList, state); } return(returnState); }