Code Style Checker: continued to implement checker for security related issues.

Wed, 10 Jun 2020 17:52:53 +0200

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Wed, 10 Jun 2020 17:52:53 +0200
changeset 7615
ca2949b1a29a
parent 7614
646742c260bd
child 7616
01d646569115

Code Style Checker: continued to implement checker for security related issues.

eric6.e4p file | annotate | diff | comparison | revisions
eric6/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleChecker.py file | annotate | diff | comparison | revisions
eric6/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleCheckerDialog.py file | annotate | diff | comparison | revisions
eric6/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleCodeSelectionDialog.py file | annotate | diff | comparison | revisions
eric6/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleStatisticsDialog.py file | annotate | diff | comparison | revisions
eric6/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleStatisticsDialog.ui file | annotate | diff | comparison | revisions
eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/generalHardcodedTmp.py file | annotate | diff | comparison | revisions
eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/injectionShell.py file | annotate | diff | comparison | revisions
eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/injectionSql.py file | annotate | diff | comparison | revisions
eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/injectionWildcard.py file | annotate | diff | comparison | revisions
eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/insecureHashlibNew.py file | annotate | diff | comparison | revisions
eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/insecureSslTls.py file | annotate | diff | comparison | revisions
eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/jinja2Templates.py file | annotate | diff | comparison | revisions
eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/makoTemplates.py file | annotate | diff | comparison | revisions
eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/sshNoHostKeyVerification.py file | annotate | diff | comparison | revisions
eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/tryExcept.py file | annotate | diff | comparison | revisions
eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/SecurityChecker.py file | annotate | diff | comparison | revisions
eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/SecurityDefaults.py file | annotate | diff | comparison | revisions
eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/SecurityUtils.py file | annotate | diff | comparison | revisions
eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/translations.py file | annotate | diff | comparison | revisions
--- a/eric6.e4p	Tue Jun 09 20:10:59 2020 +0200
+++ b/eric6.e4p	Wed Jun 10 17:52:53 2020 +0200
@@ -334,7 +334,14 @@
     <Source>eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/generalHardcodedTmp.py</Source>
     <Source>eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/injectionParamiko.py</Source>
     <Source>eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/injectionShell.py</Source>
+    <Source>eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/injectionSql.py</Source>
+    <Source>eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/injectionWildcard.py</Source>
     <Source>eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/insecureHashlibNew.py</Source>
+    <Source>eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/insecureSslTls.py</Source>
+    <Source>eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/jinja2Templates.py</Source>
+    <Source>eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/makoTemplates.py</Source>
+    <Source>eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/sshNoHostKeyVerification.py</Source>
+    <Source>eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/tryExcept.py</Source>
     <Source>eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/yamlLoad.py</Source>
     <Source>eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/SecurityChecker.py</Source>
     <Source>eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/SecurityContext.py</Source>
--- a/eric6/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleChecker.py	Tue Jun 09 20:10:59 2020 +0200
+++ b/eric6/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleChecker.py	Wed Jun 10 17:52:53 2020 +0200
@@ -111,7 +111,9 @@
             flags = [f.strip() for f in comment.split()
                      if (f.startswith("__") and f.endswith("__"))]
             flags += [f.strip().lower() for f in comment.split()
-                      if f in ("noqa", "NOQA")]
+                      if f in ("noqa", "NOQA",
+                               "nosec", "NOSEC",
+                               "secok", "SECOK")]
     return flags
 
 
@@ -130,7 +132,8 @@
         
         if (
             "__IGNORE_WARNING__" in lineFlags or
-            "noqa" in lineFlags
+            "noqa" in lineFlags or
+            "nosec" in lineFlags
         ):
             # ignore all warning codes
             return True
@@ -145,6 +148,23 @@
     return False
 
 
+def securityOk(code, lineFlags):
+    """
+    Function to check, if the given code is an acknowledged security report.
+    
+    @param code error code to be checked
+    @type str
+    @param lineFlags list of line flags to check against
+    @type list of str
+    @return flag indicating an acknowledged security report
+    @rtype bool
+    """
+    if lineFlags:
+        return "secok" in lineFlags
+    
+    return False
+
+
 def codeStyleCheck(filename, source, args):
     """
     Do the code style check and/or fix found errors.
@@ -395,6 +415,15 @@
     for lineno, errorsList in errorsDict.items():
         errorsList.sort(key=lambda x: x[0], reverse=True)
         for _, error in errorsList:
+            error.update({
+                "ignored": False,
+                "fixed": False,
+                "autofixing": False,
+                "fixcode": "",
+                "fixargs": [],
+                "securityOk": False,
+            })
+            
             if source:
                 code = error["code"]
                 lineFlags = extractLineFlags(source[lineno - 1].strip())
@@ -403,45 +432,25 @@
                                                   flagsLine=True)
                 except IndexError:
                     pass
-                if not ignoreCode(code, lineFlags):
+                
+                if securityOk(code, lineFlags):
+                    error["securityOk"] = True
+                
+                if ignoreCode(code, lineFlags):
+                    error["ignored"] = True
+                else:
                     if fixer:
-                        pass
                         res, fixcode, fixargs, id_ = fixer.fixIssue(
                             lineno, error["offset"], code)
                         if res == -1:
                             deferredFixes[id_] = error
                         else:
                             error.update({
-                                "ignored": False,
                                 "fixed": res == 1,
                                 "autofixing": True,
                                 "fixcode": fixcode,
                                 "fixargs": fixargs,
                             })
-                    else:
-                        error.update({
-                            "ignored": False,
-                            "fixed": False,
-                            "autofixing": False,
-                            "fixcode": "",
-                            "fixargs": [],
-                        })
-                else:
-                    error.update({
-                        "ignored": True,
-                        "fixed": False,
-                        "autofixing": False,
-                        "fixcode": "",
-                        "fixargs": [],
-                    })
-            else:
-                error.update({
-                    "ignored": False,
-                    "fixed": False,
-                    "autofixing": False,
-                    "fixcode": "",
-                    "fixargs": [],
-                })
             
             results.append(error)
     
--- a/eric6/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleCheckerDialog.py	Tue Jun 09 20:10:59 2020 +0200
+++ b/eric6/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleCheckerDialog.py	Wed Jun 10 17:52:53 2020 +0200
@@ -246,21 +246,23 @@
             self.__lastFileItem.setExpanded(True)
             self.__lastFileItem.setData(0, self.filenameRole, filename)
         
+        msgCode = result["code"].split(".", 1)[0]
+        
         fixable = False
         itm = QTreeWidgetItem(
             self.__lastFileItem, [
                 "{0:6}".format(result["line"]),
-                result["code"],
+                msgCode,
                 result["display"]
             ]
         )
-        if result["code"].startswith(("W", "-", "C", "M")):
+        if msgCode.startswith(("W", "-", "C", "M")):
             itm.setIcon(1, UI.PixmapCache.getIcon("warning"))
-        elif result["code"].startswith(("A", "N")):
+        elif msgCode.startswith(("A", "N")):
             itm.setIcon(1, UI.PixmapCache.getIcon("namingError"))
-        elif result["code"].startswith("D"):
+        elif msgCode.startswith("D"):
             itm.setIcon(1, UI.PixmapCache.getIcon("docstringError"))
-        elif result["code"].startswith("S"):
+        elif msgCode.startswith("S"):
             if "severity" in result:
                 if result["severity"] == "H":
                     itm.setIcon(1, UI.PixmapCache.getIcon("securityLow"))
@@ -277,9 +279,9 @@
         if result["fixed"]:
             itm.setIcon(0, UI.PixmapCache.getIcon("issueFixed"))
         elif (
-            result["code"] in FixableCodeStyleIssues and
+            msgCode in FixableCodeStyleIssues and
             not result["autofixing"] and
-            result["code"] not in self.__noFixCodesList
+            msgCode not in self.__noFixCodesList
         ):
             itm.setIcon(0, UI.PixmapCache.getIcon("issueFixable"))
             fixable = True
@@ -296,7 +298,7 @@
         itm.setData(0, self.positionRole, int(result["offset"]))
         itm.setData(0, self.messageRole, result["display"])
         itm.setData(0, self.fixableRole, fixable)
-        itm.setData(0, self.codeRole, result["code"].split(".", 1)[0])
+        itm.setData(0, self.codeRole, msgCode)
         itm.setData(0, self.ignoredRole, result["ignored"])
         itm.setData(0, self.argsRole, result["args"])
         
@@ -327,7 +329,7 @@
             itm.setIcon(0, QIcon())
         itm.setData(0, self.fixableRole, False)
     
-    def __updateStatistics(self, statistics, fixer, ignoredErrors):
+    def __updateStatistics(self, statistics, fixer, ignoredErrors, securityOk):
         """
         Private method to update the collected statistics.
         
@@ -338,6 +340,8 @@
         @type CodeStyleFixer
         @param ignoredErrors number of ignored errors
         @type int
+        @param securityOk number of acknowledged security reports
+        @type int
         """
         self.__statistics["_FilesCount"] += 1
         stats = [k for k in statistics.keys() if k[0].isupper()]
@@ -350,6 +354,7 @@
                     self.__statistics[key] = statistics[key]
         self.__statistics["_IssuesFixed"] += fixer
         self.__statistics["_IgnoredErrors"] += ignoredErrors
+        self.__statistics["_SecurityOK"] += securityOk
     
     def __updateFixerStatistics(self, fixer):
         """
@@ -369,6 +374,7 @@
         self.__statistics["_FilesIssues"] = 0
         self.__statistics["_IssuesFixed"] = 0
         self.__statistics["_IgnoredErrors"] = 0
+        self.__statistics["_SecurityOK"] = 0
     
     def prepare(self, fileList, project):
         """
@@ -812,6 +818,7 @@
         
         fixed = None
         ignoredErrors = 0
+        securityOk = 0
         if self.__itms:
             for itm, result in zip(self.__itms, results):
                 self.__modifyFixedResultItem(itm, result)
@@ -828,11 +835,16 @@
                         ).format(result["display"])
                     else:
                         continue
+                
+                elif result["securityOk"]:
+                    securityOk += 1
+                    continue
+                
                 self.results = CodeStyleCheckerDialog.hasResults
                 self.__createResultItem(fn, result)
 
             self.__updateStatistics(
-                codeStyleCheckerStats, fixes, ignoredErrors)
+                codeStyleCheckerStats, fixes, ignoredErrors, securityOk)
         
         if fixed:
             vm = e5App().getObject("ViewManager")
--- a/eric6/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleCodeSelectionDialog.py	Tue Jun 09 20:10:59 2020 +0200
+++ b/eric6/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleCodeSelectionDialog.py	Wed Jun 10 17:52:53 2020 +0200
@@ -61,7 +61,14 @@
         for code in sorted(selectableCodes):
             message = getTranslatedMessage(code, [], example=True)
             if message is None:
-                continue
+                # try with extension
+                for ext in ("L", "M", "H", "1"):
+                    message = getTranslatedMessage("{0}.{1}".format(code, ext),
+                                                   [], example=True)
+                    if message is not None:
+                        break
+                else:
+                    continue
             itm = QTreeWidgetItem(self.codeTable, [
                 code, "\n".join(textWrapper.wrap(message))])
             if code.startswith(("W", "C", "M")):
--- a/eric6/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleStatisticsDialog.py	Tue Jun 09 20:10:59 2020 +0200
+++ b/eric6/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleStatisticsDialog.py	Wed Jun 10 17:52:53 2020 +0200
@@ -40,10 +40,12 @@
         filesIssues = stats["_FilesIssues"]
         fixesCount = stats["_IssuesFixed"]
         ignoresCount = stats["_IgnoredErrors"]
+        securityOk = stats["_SecurityOK"]
         del stats["_FilesCount"]
         del stats["_FilesIssues"]
         del stats["_IssuesFixed"]
         del stats["_IgnoredErrors"]
+        del stats["_SecurityOK"]
         
         totalIssues = 0
         
@@ -68,6 +70,8 @@
             self.tr("%n file(s) checked", "", filesCount))
         self.filesIssues.setText(
             self.tr("%n file(s) with issues found", "", filesIssues))
+        self.securityOk.setText(
+            self.tr("%n security issue(s) acknowledged", "", securityOk))
         
         self.statisticsList.resizeColumnToContents(0)
         self.statisticsList.resizeColumnToContents(1)
@@ -93,5 +97,5 @@
         elif code.startswith("S"):
             itm.setIcon(1, UI.PixmapCache.getIcon("securityLow"))
         
-        itm.setTextAlignment(0, Qt.AlignRight)
-        itm.setTextAlignment(1, Qt.AlignHCenter)
+        itm.setTextAlignment(0, Qt.AlignRight | Qt.AlignVCenter)
+        itm.setTextAlignment(1, Qt.AlignHCenter | Qt.AlignVCenter)
--- a/eric6/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleStatisticsDialog.ui	Tue Jun 09 20:10:59 2020 +0200
+++ b/eric6/Plugins/CheckerPlugins/CodeStyleChecker/CodeStyleStatisticsDialog.ui	Wed Jun 10 17:52:53 2020 +0200
@@ -59,6 +59,9 @@
      <item row="2" column="0">
       <widget class="QLabel" name="fixedIssues"/>
      </item>
+     <item row="2" column="1">
+      <widget class="QLabel" name="securityOk"/>
+     </item>
     </layout>
    </item>
    <item>
--- a/eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/generalHardcodedTmp.py	Tue Jun 09 20:10:59 2020 +0200
+++ b/eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/generalHardcodedTmp.py	Wed Jun 10 17:52:53 2020 +0200
@@ -13,7 +13,9 @@
 # Original Copyright 2014 Hewlett-Packard Development Company, L.P.
 #
 # SPDX-License-Identifier: Apache-2.0
-#
+#...r\Security\Checks\generalHardcodedTmp.py
+
+from Security.SecurityDefaults import SecurityDefaults
 
 
 def getChecks():
@@ -45,7 +47,7 @@
     if config and "hardcoded_tmp_directories" in config:
         tmpDirs = config["hardcoded_tmp_directories"]
     else:
-        tmpDirs = ["/tmp", "/var/tmp", "/dev/shm", "~/tmp"]
+        tmpDirs = SecurityDefaults["hardcoded_tmp_directories"]
     
     if any(context.stringVal.startswith(s) for s in tmpDirs):
         reportError(
--- a/eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/injectionShell.py	Tue Jun 09 20:10:59 2020 +0200
+++ b/eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/injectionShell.py	Wed Jun 10 17:52:53 2020 +0200
@@ -19,6 +19,8 @@
 import re
 import sys
 
+from Security.SecurityDefaults import SecurityDefaults
+
 # This regex starts with a windows drive letter (eg C:)
 # or one of our path delimeter characters (/, \, .)
 fullPathMatchRe = re.compile(r'^(?:[A-Za-z](?=\:)|[\\\/\.])')
@@ -44,62 +46,6 @@
     }
 
 
-def _defaultValues(key):
-    """
-    Function to get the default values for a given check key.
-    
-    @param key key to get default values for
-    @type str
-    @return list with default values
-    @rtype list of str
-    """
-    if key == "shell_injection_subprocess":
-        return [
-            'subprocess.Popen',
-            'subprocess.call',
-            'subprocess.check_call',
-            'subprocess.check_output',
-            'subprocess.run'
-        ]
-    elif key == "shell_injection_shell":
-        return [
-            'os.system',
-            'os.popen',
-            'os.popen2',
-            'os.popen3',
-            'os.popen4',
-            'popen2.popen2',
-            'popen2.popen3',
-            'popen2.popen4',
-            'popen2.Popen3',
-            'popen2.Popen4',
-            'commands.getoutput',
-            'commands.getstatusoutput'
-        ]
-    elif key == "shell_injection_noshell":
-        return [
-            'os.execl',
-            'os.execle',
-            'os.execlp',
-            'os.execlpe',
-            'os.execv',
-            'os.execve',
-            'os.execvp',
-            'os.execvpe',
-            'os.spawnl',
-            'os.spawnle',
-            'os.spawnlp',
-            'os.spawnlpe',
-            'os.spawnv',
-            'os.spawnve',
-            'os.spawnvp',
-            'os.spawnvpe',
-            'os.startfile'
-        ]
-    else:
-        return []
-
-
 def _evaluateShellCall(context):
     """
     Function to determine the severity of a shell call.
@@ -168,7 +114,7 @@
     if config and "shell_injection_subprocess" in config:
         functionNames = config["shell_injection_subprocess"]
     else:
-        functionNames = _defaultValues("shell_injection_subprocess")
+        functionNames = SecurityDefaults["shell_injection_subprocess"]
     
     if context.callFunctionNameQual in functionNames:
         shell, shellValue = hasShell(context)
@@ -207,7 +153,7 @@
     if config and "shell_injection_subprocess" in config:
         functionNames = config["shell_injection_subprocess"]
     else:
-        functionNames = _defaultValues("shell_injection_subprocess")
+        functionNames = SecurityDefaults["shell_injection_subprocess"]
     
     if context.callFunctionNameQual in functionNames:
         if not hasShell(context)[0]:
@@ -234,7 +180,7 @@
     if config and "shell_injection_subprocess" in config:
         functionNames = config["shell_injection_subprocess"]
     else:
-        functionNames = _defaultValues("shell_injection_subprocess")
+        functionNames = SecurityDefaults["shell_injection_subprocess"]
     
     if context.callFunctionNameQual not in functionNames:
         shell, shellValue = hasShell(context)
@@ -262,7 +208,7 @@
     if config and "shell_injection_shell" in config:
         functionNames = config["shell_injection_shell"]
     else:
-        functionNames = _defaultValues("shell_injection_shell")
+        functionNames = SecurityDefaults["shell_injection_shell"]
     
     if context.callFunctionNameQual in functionNames:
         if len(context.callArgs) > 0:
@@ -299,7 +245,7 @@
     if config and "shell_injection_noshell" in config:
         functionNames = config["shell_injection_noshell"]
     else:
-        functionNames = _defaultValues("shell_injection_noshell")
+        functionNames = SecurityDefaults["shell_injection_noshell"]
     
     if context.callFunctionNameQual in functionNames:
         reportError(
@@ -325,17 +271,17 @@
     if config and "shell_injection_subprocess" in config:
         functionNames = config["shell_injection_subprocess"]
     else:
-        functionNames = _defaultValues("shell_injection_subprocess")
+        functionNames = SecurityDefaults["shell_injection_subprocess"]
     
     if config and "shell_injection_shell" in config:
         functionNames += config["shell_injection_shell"]
     else:
-        functionNames += _defaultValues("shell_injection_shell")
+        functionNames += SecurityDefaults["shell_injection_shell"]
     
     if config and "shell_injection_noshell" in config:
         functionNames += config["shell_injection_noshell"]
     else:
-        functionNames += _defaultValues("shell_injection_noshell")
+        functionNames += SecurityDefaults["shell_injection_noshell"]
     
     if len(context.callArgs):
         if context.callFunctionNameQual in functionNames:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/injectionSql.py	Wed Jun 10 17:52:53 2020 +0200
@@ -0,0 +1,118 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2020 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a check for SQL injection.
+"""
+
+#
+# This is a modified version of the one found in the bandit package.
+#
+# Original Copyright 2014 Hewlett-Packard Development Company, L.P.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+import ast
+import re
+
+from Security import SecurityUtils
+
+
+def getChecks():
+    """
+    Public method to get a dictionary with checks handled by this module.
+    
+    @return dictionary containing checker lists containing checker function and
+        list of codes
+    @rtype dict
+    """
+    return {
+        "Str": [
+            (checkHardcodedSqlExpressions, ("S608",)),
+        ],
+    }
+
+
+SIMPLE_SQL_RE = re.compile(
+    r'(select\s.*from\s|'
+    r'delete\s+from\s|'
+    r'insert\s+into\s.*values\s|'
+    r'update\s.*set\s)',
+    re.IGNORECASE | re.DOTALL,
+)
+
+
+def _checkString(data):
+    """
+    Function to check a given string against the list of search patterns.
+    
+    @param data string data to be checked
+    @type str
+    @return flag indicating a match
+    @rtype bool
+    """
+    return SIMPLE_SQL_RE.search(data) is not None
+
+
+def _evaluateAst(node):
+    """
+    Function to analyze the given ast node.
+    
+    @param node ast node to be analyzed
+    @type ast.Str
+    @return tuple containing a flag indicating an execute call and
+        the resulting statement
+    @rtype tuple of (bool, str)
+    """
+    wrapper = None
+    statement = ''
+
+    if isinstance(node._securityParent, ast.BinOp):
+        out = SecurityUtils.concatString(node, node._securityParent)
+        wrapper = out[0]._securityParent
+        statement = out[1]
+    elif (
+        isinstance(node._securityParent, ast.Attribute) and
+        node._securityParent.attr == 'format'
+    ):
+        statement = node.s
+        # Hierarchy for "".format() is Wrapper -> Call -> Attribute -> Str
+        wrapper = node._securityParent._securityParent._securityParent
+    elif (
+        hasattr(ast, 'JoinedStr') and
+        isinstance(node._securityParent, ast.JoinedStr)
+    ):
+        statement = node.s
+        wrapper = node._securityParent._securityParent
+    
+    if isinstance(wrapper, ast.Call):  # wrapped in "execute" call?
+        names = ['execute', 'executemany']
+        name = SecurityUtils.getCalledName(wrapper)
+        return (name in names, statement)
+    else:
+        return (False, statement)
+
+
+def checkHardcodedSqlExpressions(reportError, context, config):
+    """
+    Function to check for SQL injection.
+    
+    @param reportError function to be used to report errors
+    @type func
+    @param context security context object
+    @type SecurityContext
+    @param config dictionary with configuration data
+    @type dict
+    """
+    val = _evaluateAst(context.node)
+    if _checkString(val[1]):
+        reportError(
+            context.node.lineno - 1,
+            context.node.col_offset,
+            "S608",
+            "M",
+            "M" if val[0] else "L",
+        )
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/injectionWildcard.py	Wed Jun 10 17:52:53 2020 +0200
@@ -0,0 +1,92 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2020 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a check for use of wildcard injection.
+"""
+
+#
+# This is a modified version of the one found in the bandit package.
+#
+# Original Copyright 2014 Hewlett-Packard Development Company, L.P.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+from Security.SecurityDefaults import SecurityDefaults
+
+
+def getChecks():
+    """
+    Public method to get a dictionary with checks handled by this module.
+    
+    @return dictionary containing checker lists containing checker function and
+        list of codes
+    @rtype dict
+    """
+    return {
+        "Call": [
+            (checkLinuxCommandsWildcardInjection, ("S609",)),
+        ],
+    }
+
+
+def checkLinuxCommandsWildcardInjection(reportError, context, config):
+    """
+    Function to check for use of wildcard injection.
+    
+    @param reportError function to be used to report errors
+    @type func
+    @param context security context object
+    @type SecurityContext
+    @param config dictionary with configuration data
+    @type dict
+    """
+    if config and "shell_injection_subprocess" in config:
+        subProcessFunctionNames = config["shell_injection_subprocess"]
+    else:
+        subProcessFunctionNames = SecurityDefaults[
+            "shell_injection_subprocess"]
+    
+    if config and "shell_injection_shell" in config:
+        shellFunctionNames = config["shell_injection_shell"]
+    else:
+        shellFunctionNames = SecurityDefaults["shell_injection_shell"]
+    
+    vulnerableFunctions = ['chown', 'chmod', 'tar', 'rsync']
+    if (
+        context.callFunctionNameQual in shellFunctionNames or
+        (context.callFunctionNameQual in subProcessFunctionNames and
+         context.checkCallArgValue('shell', 'True'))
+    ):
+        if context.callArgsCount >= 1:
+            callArgument = context.getCallArgAtPosition(0)
+            argumentString = ''
+            if isinstance(callArgument, list):
+                for li in callArgument:
+                    argumentString = argumentString + ' {0}'.format(li)
+            elif isinstance(callArgument, str):
+                argumentString = callArgument
+            
+            if argumentString != '':
+                for vulnerableFunction in vulnerableFunctions:
+                    if (
+                        vulnerableFunction in argumentString and
+                        '*' in argumentString
+                    ):
+                        lineNo = context.getLinenoForCallArg('shell')
+                        if lineNo < 1:
+                            lineNo = context.node.lineno
+                        offset = context.getOffsetForCallArg('shell')
+                        if offset < 0:
+                            offset = context.node.col_offset
+                        reportError(
+                            lineNo - 1,
+                            offset,
+                            "S609",
+                            "H",
+                            "M",
+                            context.callFunctionNameQual
+                        )
--- a/eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/insecureHashlibNew.py	Tue Jun 09 20:10:59 2020 +0200
+++ b/eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/insecureHashlibNew.py	Wed Jun 10 17:52:53 2020 +0200
@@ -16,6 +16,8 @@
 # SPDX-License-Identifier: Apache-2.0
 #
 
+from Security.SecurityDefaults import SecurityDefaults
+
 
 def getChecks():
     """
@@ -47,7 +49,7 @@
     if config and "insecure_hashes" in config:
         insecureHashes = [h.lower() for h in config["insecure_hashes"]]
     else:
-        insecureHashes = ['md4', 'md5', 'sha', 'sha1']
+        insecureHashes = SecurityDefaults["insecure_hashes"]
     
     if isinstance(context.callFunctionNameQual, str):
         qualnameList = context.callFunctionNameQual.split('.')
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/insecureSslTls.py	Wed Jun 10 17:52:53 2020 +0200
@@ -0,0 +1,153 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2020 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a check for use of SSL/TLS with insecure protocols.
+"""
+
+#
+# This is a modified version of the one found in the bandit package.
+#
+# Original Copyright 2014 Hewlett-Packard Development Company, L.P.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+from Security.SecurityDefaults import SecurityDefaults
+
+
+def getChecks():
+    """
+    Public method to get a dictionary with checks handled by this module.
+    
+    @return dictionary containing checker lists containing checker function and
+        list of codes
+    @rtype dict
+    """
+    return {
+        "Call": [
+            (checkInsecureSslProtocolVersion, ("S502",)),
+            (checkSslWithoutVersion, ("S504",)),
+        ],
+        "FunctionDef": [
+            (checkInsecureSslDefaults, ("S503",)),
+        ],
+    }
+
+
+def checkInsecureSslProtocolVersion(reportError, context, config):
+    """
+    Function to check for use of insecure SSL protocol version.
+    
+    @param reportError function to be used to report errors
+    @type func
+    @param context security context object
+    @type SecurityContext
+    @param config dictionary with configuration data
+    @type dict
+    """
+    if config and "insecure_ssl_protocol_versions" in config:
+        insecureProtocolVersions = config["insecure_ssl_protocol_versions"]
+    else:
+        insecureProtocolVersions = SecurityDefaults[
+            "insecure_ssl_protocol_versions"]
+    
+    if context.callFunctionNameQual == 'ssl.wrap_socket':
+        if context.checkCallArgValue('ssl_version', insecureProtocolVersions):
+            reportError(
+                context.getLinenoForCallArg('ssl_version') - 1,
+                context.getOffsetForCallArg('ssl_version'),
+                "S502.1",
+                "H",
+                "H",
+            )
+    
+    elif context.callFunctionNameQual == 'pyOpenSSL.SSL.Context':
+        if context.checkCallArgValue('method', insecureProtocolVersions):
+            reportError(
+                context.getLinenoForCallArg('method') - 1,
+                context.getOffsetForCallArg('method'),
+                "S502.2",
+                "H",
+                "H",
+            )
+    
+    elif (
+        context.callFunctionNameQual != 'ssl.wrap_socket' and
+        context.callFunctionNameQual != 'pyOpenSSL.SSL.Context'
+    ):
+        if context.checkCallArgValue('method', insecureProtocolVersions):
+            reportError(
+                context.getLinenoForCallArg('method') - 1,
+                context.getOffsetForCallArg('method'),
+                "S502.3",
+                "H",
+                "H",
+            )
+        
+        elif context.checkCallArgValue('ssl_version',
+                                       insecureProtocolVersions):
+            reportError(
+                context.getLinenoForCallArg('ssl_version') - 1,
+                context.getOffsetForCallArg('ssl_version'),
+                "S502.3",
+                "H",
+                "H",
+            )
+
+
+def checkInsecureSslDefaults(reportError, context, config):
+    """
+    Function to check for SSL use with insecure defaults specified.
+    
+    @param reportError function to be used to report errors
+    @type func
+    @param context security context object
+    @type SecurityContext
+    @param config dictionary with configuration data
+    @type dict
+    """
+    if config and "insecure_ssl_protocol_versions" in config:
+        insecureProtocolVersions = config["insecure_ssl_protocol_versions"]
+    else:
+        insecureProtocolVersions = SecurityDefaults[
+            "insecure_ssl_protocol_versions"]
+    
+    for default in context.functionDefDefaultsQual:
+        val = default.split(".")[-1]
+        if val in insecureProtocolVersions:
+            reportError(
+                context.node.lineno - 1,
+                context.node.col_offset,
+                "S503",
+                "M",
+                "M",
+            )
+
+
+def checkSslWithoutVersion(reportError, context, config):
+    """
+    Function to check for SSL use with no version specified.
+    
+    @param reportError function to be used to report errors
+    @type func
+    @param context security context object
+    @type SecurityContext
+    @param config dictionary with configuration data
+    @type dict
+    """
+    if context.callFunctionNameQual == 'ssl.wrap_socket':
+        if context.checkCallArgValue('ssl_version') is None:
+            # checkCallArgValue() returns False if the argument is found
+            # but does not match the supplied value (or the default None).
+            # It returns None if the argument passed doesn't exist. This
+            # tests for that (ssl_version is not specified).
+            reportError(
+                context.node.lineno - 1,
+                context.node.col_offset,
+                "S504",
+                "L",
+                "M",
+            )
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/jinja2Templates.py	Wed Jun 10 17:52:53 2020 +0200
@@ -0,0 +1,105 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2020 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a check for not auto escaping in jinja2.
+"""
+
+#
+# This is a modified version of the one found in the bandit package.
+#
+# Original Copyright 2014 Hewlett-Packard Development Company, L.P.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+import ast
+
+
+def getChecks():
+    """
+    Public method to get a dictionary with checks handled by this module.
+    
+    @return dictionary containing checker lists containing checker function and
+        list of codes
+    @rtype dict
+    """
+    return {
+        "Call": [
+            (checkJinja2Autoescape, ("S701",)),
+        ],
+    }
+
+
+def checkJinja2Autoescape(reportError, context, config):
+    """
+    Function to check for not auto escaping in jinja2.
+    
+    @param reportError function to be used to report errors
+    @type func
+    @param context security context object
+    @type SecurityContext
+    @param config dictionary with configuration data
+    @type dict
+    """
+    if isinstance(context.callFunctionNameQual, str):
+        qualnameList = context.callFunctionNameQual.split('.')
+        func = qualnameList[-1]
+        if 'jinja2' in qualnameList and func == 'Environment':
+            for node in ast.walk(context.node):
+                if isinstance(node, ast.keyword):
+                    # definite autoescape = False
+                    if (
+                        getattr(node, 'arg', None) == 'autoescape' and
+                        (
+                            getattr(node.value, 'id', None) == 'False' or
+                            getattr(node.value, 'value', None) is False
+                        )
+                    ):
+                        reportError(
+                            context.node.lineno - 1,
+                            context.node.col_offset,
+                            "S701.1",
+                            "H",
+                            "H",
+                        )
+                        return
+                    
+                    # found autoescape
+                    if getattr(node, 'arg', None) == 'autoescape':
+                        value = getattr(node, 'value', None)
+                        if (
+                            getattr(value, 'id', None) == 'True' or
+                            getattr(value, 'value', None) is True
+                        ):
+                            return
+                        
+                        # Check if select_autoescape function is used.
+                        elif (
+                            isinstance(value, ast.Call) and
+                            (getattr(value.func, 'id', None) ==
+                             'select_autoescape')
+                        ):
+                            return
+                        
+                        else:
+                            reportError(
+                                context.node.lineno - 1,
+                                context.node.col_offset,
+                                "S701.1",
+                                "H",
+                                "M",
+                            )
+                            return
+            
+            # We haven't found a keyword named autoescape, indicating default
+            # behavior
+            reportError(
+                context.node.lineno - 1,
+                context.node.col_offset,
+                "S701.2",
+                "H",
+                "H",
+            )
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/makoTemplates.py	Wed Jun 10 17:52:53 2020 +0200
@@ -0,0 +1,57 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2020 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a check for use of mako templates.
+"""
+
+#
+# This is a modified version of the one found in the bandit package.
+#
+# Original Copyright 2014 Hewlett-Packard Development Company, L.P.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+
+def getChecks():
+    """
+    Public method to get a dictionary with checks handled by this module.
+    
+    @return dictionary containing checker lists containing checker function and
+        list of codes
+    @rtype dict
+    """
+    return {
+        "Call": [
+            (checkMakoTemplateUsage, ("S702",)),
+        ],
+    }
+
+
+def checkMakoTemplateUsage(reportError, context, config):
+    """
+    Function to check for use of mako templates.
+    
+    @param reportError function to be used to report errors
+    @type func
+    @param context security context object
+    @type SecurityContext
+    @param config dictionary with configuration data
+    @type dict
+    """
+    if isinstance(context.callFunctionNameQual, str):
+        qualnameList = context.callFunctionNameQual.split('.')
+        func = qualnameList[-1]
+        if 'mako' in qualnameList and func == 'Template':
+            # unlike Jinja2, mako does not have a template wide autoescape
+            # feature and thus each variable must be carefully sanitized.
+            reportError(
+                context.node.lineno - 1,
+                context.node.col_offset,
+                "S702",
+                "M",
+                "H",
+            )
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/sshNoHostKeyVerification.py	Wed Jun 10 17:52:53 2020 +0200
@@ -0,0 +1,59 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2020 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a check for use of mako templates.
+"""
+
+#
+# This is a modified version of the one found in the bandit package.
+#
+# Original Copyright 2014 Hewlett-Packard Development Company, L.P.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+
+def getChecks():
+    """
+    Public method to get a dictionary with checks handled by this module.
+    
+    @return dictionary containing checker lists containing checker function and
+        list of codes
+    @rtype dict
+    """
+    return {
+        "Call": [
+            (checkSshNoHostKeyVerification, ("S507",)),
+        ],
+    }
+
+
+def checkSshNoHostKeyVerification(reportError, context, config):
+    """
+    Function to check for use of mako templates.
+    
+    @param reportError function to be used to report errors
+    @type func
+    @param context security context object
+    @type SecurityContext
+    @param config dictionary with configuration data
+    @type dict
+    """
+    if (
+        context.isModuleImportedLike('paramiko') and
+        context.callFunctionName == 'set_missing_host_key_policy'
+    ):
+        if (
+            context.callArgs and
+            context.callArgs[0] in ['AutoAddPolicy', 'WarningPolicy']
+        ):
+            reportError(
+                context.node.lineno - 1,
+                context.node.col_offset,
+                "S507",
+                "H",
+                "M",
+            )
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/Checks/tryExcept.py	Wed Jun 10 17:52:53 2020 +0200
@@ -0,0 +1,106 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2020 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing checks for insecure except blocks.
+"""
+
+#
+# This is a modified version of the one found in the bandit package.
+#
+# Original Copyright 2014 Hewlett-Packard Development Company, L.P.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+import ast
+
+from Security.SecurityDefaults import SecurityDefaults
+
+
+def getChecks():
+    """
+    Public method to get a dictionary with checks handled by this module.
+    
+    @return dictionary containing checker lists containing checker function and
+        list of codes
+    @rtype dict
+    """
+    return {
+        "ExceptHandler": [
+            (checkTryExceptPass, ("S110",)),
+            (checkTryExceptContinue, ("S112",)),
+        ],
+    }
+
+
+def checkTryExceptPass(reportError, context, config):
+    """
+    Function to check for a pass in the except block.
+    
+    @param reportError function to be used to report errors
+    @type func
+    @param context security context object
+    @type SecurityContext
+    @param config dictionary with configuration data
+    @type dict
+    """
+    if config and "check_typed_exception" in config:
+        checkTypedException = config["check_typed_exception"]
+    else:
+        checkTypedException = SecurityDefaults["check_typed_exception"]
+    
+    node = context.node
+    if len(node.body) == 1:
+        if (
+            not checkTypedException and
+            node.type is not None and
+            getattr(node.type, 'id', None) != 'Exception'
+        ):
+            return
+        
+        if isinstance(node.body[0], ast.Pass):
+            reportError(
+                context.node.lineno - 1,
+                context.node.col_offset,
+                "S110",
+                "L",
+                "H",
+            )
+
+
+def checkTryExceptContinue(reportError, context, config):
+    """
+    Function to check for a continue in the except block.
+    
+    @param reportError function to be used to report errors
+    @type func
+    @param context security context object
+    @type SecurityContext
+    @param config dictionary with configuration data
+    @type dict
+    """
+    if config and "check_typed_exception" in config:
+        checkTypedException = config["check_typed_exception"]
+    else:
+        checkTypedException = SecurityDefaults["check_typed_exception"]
+    
+    node = context.node
+    if len(node.body) == 1:
+        if (
+            not checkTypedException and
+            node.type is not None and
+            getattr(node.type, 'id', None) != 'Exception'
+        ):
+            return
+        
+        if isinstance(node.body[0], ast.Continue):
+            reportError(
+                context.node.lineno - 1,
+                context.node.col_offset,
+                "S112",
+                "L",
+                "H",
+            )
--- a/eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/SecurityChecker.py	Tue Jun 09 20:10:59 2020 +0200
+++ b/eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/SecurityChecker.py	Wed Jun 10 17:52:53 2020 +0200
@@ -38,6 +38,9 @@
         # hardcoded tmp directory
         "S108",
         
+        # try-except
+        "S110", "S112",
+        
         # flask app
         "S201",
         
@@ -55,17 +58,38 @@
         # insecure certificate usage
         "S501",
         
+        # insecure SSL/TLS protocol version
+        "S502", "S503", "S504",
+        
         # YAML load
         "S506",
         
+        # SSH host key verification
+        "S507",
+        
         # Shell injection
         "S601", "S602", "S603", "S604", "S605", "S606", "S607",
         
+        # SQL injection
+        "S608",
+        
+        # Wildcard injection
+        "S609",
+        
         # Django SQL injection
         "S610", "S611",
         
+        # Jinja2 templates
+        "S701",
+        
+        # Mako templates
+        "S702",
+        
         # Django XSS vulnerability
         "S703",
+        
+        # Syntax error
+        "S999",
     ]
     
     def __init__(self, source, filename, select, ignore, expected, repeat,
--- a/eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/SecurityDefaults.py	Tue Jun 09 20:10:59 2020 +0200
+++ b/eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/SecurityDefaults.py	Wed Jun 10 17:52:53 2020 +0200
@@ -8,14 +8,23 @@
 """
 
 SecurityDefaults = {
+    # generalHardcodedTmp.py
     "hardcoded_tmp_directories": ["/tmp", "/var/tmp", "/dev/shm", "~/tmp"],
+    
+    # insecureHashlibNew.py
     "insecure_hashes": ['md4', 'md5', 'sha', 'sha1'],
+    
+    # injectionShell.py
+    # injectionWildcard.py
     "shell_injection_subprocess": [
         'subprocess.Popen',
         'subprocess.call',
         'subprocess.check_call',
         'subprocess.check_output',
         'subprocess.run'],
+    
+    # injectionShell.py
+    # injectionWildcard.py
     "shell_injection_shell": [
         'os.system',
         'os.popen',
@@ -29,6 +38,8 @@
         'popen2.Popen4',
         'commands.getoutput',
         'commands.getstatusoutput'],
+    
+    # injectionShell.py
     "shell_injection_noshell": [
         'os.execl',
         'os.execle',
@@ -47,4 +58,17 @@
         'os.spawnvp',
         'os.spawnvpe',
         'os.startfile'],
+    
+    # insecureSslTls.py
+    "insecure_ssl_protocol_versions": [
+        'PROTOCOL_SSLv2',
+        'SSLv2_METHOD',
+        'SSLv23_METHOD',
+        'PROTOCOL_SSLv3',
+        'PROTOCOL_TLSv1',
+        'SSLv3_METHOD',
+        'TLSv1_METHOD'],
+    
+    # tryExcept.py
+    "check_typed_exception": False, 
 }
--- a/eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/SecurityUtils.py	Tue Jun 09 20:10:59 2020 +0200
+++ b/eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/SecurityUtils.py	Wed Jun 10 17:52:53 2020 +0200
@@ -258,3 +258,67 @@
     @rtype bytes
     """
     return b.decode('unicode_escape').encode('unicode_escape')
+
+
+def concatString(node, stop=None):
+    """
+    Function to build a string from an ast.BinOp chain.
+
+    This will build a string from a series of ast.Str nodes wrapped in
+    ast.BinOp nodes. Something like "a" + "b" + "c" or "a %s" % val etc.
+    The provided node can be any participant in the BinOp chain.
+    
+    @param node node to be processed
+    @type ast.BinOp or ast.Str
+    @param stop base node to stop at
+    @type ast.BinOp or ast.Str
+    @return tuple containing the root node of the expression and the string
+        value
+    @rtype tuple of (ast.AST, str)
+    """
+    def _get(node, bits, stop=None):
+        if node != stop:
+            bits.append(
+                _get(node.left, bits, stop)
+                if isinstance(node.left, ast.BinOp)
+                else node.left
+            )
+            bits.append(
+                _get(node.right, bits, stop)
+                if isinstance(node.right, ast.BinOp)
+                else node.right
+            )
+    
+    bits = [node]
+    while isinstance(node._securityParent, ast.BinOp):
+        node = node._securityParent
+    if isinstance(node, ast.BinOp):
+        _get(node, bits, stop)
+    
+    return (
+        node,
+        " ".join([x.s for x in bits if isinstance(x, ast.Str)])
+    )
+
+
+def getCalledName(node):
+    """
+    Function to get the function name from an ast.Call node.
+    
+    An ast.Call node representing a method call will present differently to one
+    wrapping a function call: thing.call() vs call(). This helper will grab the
+    unqualified call name correctly in either case.
+    
+    @param node reference to the call node
+    @type ast.Call
+    @return function name of the node
+    @rtype str
+    """
+    func = node.func
+    try:
+        return func.attr if isinstance(func, ast.Attribute) else func.id
+    except AttributeError:
+        return ""
+
+#
+# eflag: noqa = M601
--- a/eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/translations.py	Tue Jun 09 20:10:59 2020 +0200
+++ b/eric6/Plugins/CheckerPlugins/CodeStyleChecker/Security/translations.py	Wed Jun 10 17:52:53 2020 +0200
@@ -49,6 +49,14 @@
         "Security",
         "Probable insecure usage of temp file/directory."),
     
+    # try-except
+    "S110": QCoreApplication.translate(
+        "Security",
+        "Try, Except, Pass detected."),
+    "S112": QCoreApplication.translate(
+        "Security",
+        "Try, Except, Continue detected."),
+    
     # flask app
     "S201": QCoreApplication.translate(
         "Security",
@@ -236,12 +244,40 @@
         "'requests' call with verify=False disabling SSL certificate checks,"
         " security issue."),
     
+    # insecure SSL/TLS protocol version
+    "S502.1": QCoreApplication.translate(
+        "Security",
+        "'ssl.wrap_socket' call with insecure SSL/TLS protocol version"
+        " identified, security issue."),
+    "S502.2": QCoreApplication.translate(
+        "Security",
+        "'SSL.Context' call with insecure SSL/TLS protocol version identified,"
+        " security issue."),
+    "S502.3": QCoreApplication.translate(
+        "Security",
+        "Function call with insecure SSL/TLS protocol version identified,"
+        " security issue."),
+    "S503": QCoreApplication.translate(
+        "Security",
+        "Function definition identified with insecure SSL/TLS protocol"
+        " version by default, possible security issue."),
+    "S504": QCoreApplication.translate(
+        "Security",
+        "'ssl.wrap_socket' call with no SSL/TLS protocol version specified,"
+        " the default 'SSLv23' could be insecure, possible security issue."),
+    
     # YAML load
     "S506": QCoreApplication.translate(
         "Security",
         "Use of unsafe 'yaml.load()'. Allows instantiation of arbitrary"
         " objects. Consider 'yaml.safe_load()'."),
     
+    # SSH host key verification
+    "S507": QCoreApplication.translate(
+        "Security",
+        "Paramiko call with policy set to automatically trust the unknown"
+        " host key."),
+    
     # Shell injection
     "S601": QCoreApplication.translate(
         "Security",
@@ -276,6 +312,17 @@
         "Security",
         "Starting a process with a partial executable path."),
     
+    # SQL injection
+    "S608": QCoreApplication.translate(
+        "Security",
+        "Possible SQL injection vector through string-based query"
+        " construction."),
+    
+    # Wildcard injection
+    "S609": QCoreApplication.translate(
+        "Security",
+        "Possible wildcard injection in call: {0}"),
+    
     # Django SQL injection
     "S610": QCoreApplication.translate(
         "Security",
@@ -284,11 +331,32 @@
         "Security",
         "Use of 'RawSQL()' opens a potential SQL attack vector."),
     
+    # Jinja2 templates
+    "S701.1": QCoreApplication.translate(
+        "Security",
+        "Using jinja2 templates with 'autoescape=False' is dangerous and can"
+        " lead to XSS. Use 'autoescape=True' or use the 'select_autoescape'"
+        " function to mitigate XSS vulnerabilities."),
+    "S701.2": QCoreApplication.translate(
+        "Security",
+        "By default, jinja2 sets 'autoescape' to False. Consider using"
+        " 'autoescape=True' or use the 'select_autoescape' function to"
+        " mitigate XSS vulnerabilities."),
+    
+    # Mako templates
+    "S702": QCoreApplication.translate(
+        "Security",
+        "Mako templates allow HTML/JS rendering by default and are inherently"
+        " open to XSS attacks. Ensure variables in all templates are properly"
+        " sanitized via the 'n', 'h' or 'x' flags (depending on context). For"
+        " example, to HTML escape the variable 'data' do ${{ data |h }}."),
+    
     # Django XSS vulnerability
     "S703": QCoreApplication.translate(
         "Security",
         "Potential XSS on 'mark_safe()' function."),
     
+    # Syntax error
     "S999": QCoreApplication.translate(
         "Security",
         "{0}: {1}"),
@@ -329,5 +397,7 @@
     "S412": ["wsgiref.handlers.CGIHandler"],
     "S413": ["Crypto.Cipher"],
     
+    "S609": ["os.system"],
+    
     "S999": ["SyntaxError", "Invalid Syntax"],
 }

eric ide

mercurial