diff --git a/.editorconfig b/.editorconfig
index 17d087db6..0b244df1e 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -31,7 +31,7 @@ trim_trailing_whitespace = false
 indent_style = space
 indent_size = 4
 
-[*.ini]
+[{*.ini,.bandit,.flake8}]
 charset = latin1
 indent_style = space
 indent_size = 4
diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml
index b2a3ca237..be8b5813b 100644
--- a/.github/workflows/python.yml
+++ b/.github/workflows/python.yml
@@ -48,6 +48,30 @@ jobs:
       - name: Run tox
         run: poetry run tox run -e flake8 -s false
 
+  security-issues:
+    name: find Security Issues
+    runs-on: ubuntu-latest
+    timeout-minutes: 10
+    steps:
+      - name: Checkout
+        # see https://github.com/actions/checkout
+        uses: actions/checkout@v4
+      - name: Setup Python Environment
+        # see https://github.com/actions/setup-python
+        uses: actions/setup-python@v4
+        with:
+          python-version: ${{ env.PYTHON_VERSION_DEFAULT }}
+          architecture: 'x64'
+      - name: Install poetry
+        # see https://github.com/marketplace/actions/setup-poetry
+        uses: Gr1N/setup-poetry@v8
+        with:
+          poetry-version: ${{ env.POETRY_VERSION }}
+      - name: Install dependencies
+        run: poetry install --no-root
+      - name: Run tox
+        run: poetry run tox run -e bandit -s false
+
   static-code-analysis:
     name: StaticCodingAnalysis (py${{ matrix.python-version}} ${{ matrix.toxenv-factors }})
     runs-on: ${{ matrix.os }}
diff --git a/bandit.yml b/bandit.yml
new file mode 100644
index 000000000..03d6ead6f
--- /dev/null
+++ b/bandit.yml
@@ -0,0 +1,9 @@
+# https://bandit.readthedocs.io
+# filename must be like this, so codacy can pick it up: https://github.com/codacy/codacy-bandit/blob/master/src/main/scala/codacy/bandit/Bandit.scala#L35C49-L35C59
+
+exclude_dirs:
+  - docs
+  - .venv
+
+skips:
+  - B101
diff --git a/cyclonedx/model/__init__.py b/cyclonedx/model/__init__.py
index 5b5b0d8b8..5441049c1 100644
--- a/cyclonedx/model/__init__.py
+++ b/cyclonedx/model/__init__.py
@@ -55,7 +55,7 @@ def sha1sum(filename: str) -> str:
     Returns:
         SHA-1 hash
     """
-    h = sha1()
+    h = sha1()  # nosec B303, B324
     with open(filename, 'rb') as f:
         for byte_block in iter(lambda: f.read(4096), b''):
             h.update(byte_block)
diff --git a/cyclonedx/output/xml.py b/cyclonedx/output/xml.py
index b57e2db89..1f5981130 100644
--- a/cyclonedx/output/xml.py
+++ b/cyclonedx/output/xml.py
@@ -17,8 +17,8 @@
 
 
 from typing import TYPE_CHECKING, Any, Dict, Literal, Optional, Type, Union
-from xml.dom.minidom import parseString as dom_parseString
-from xml.etree.ElementTree import Element as XmlElement, tostring as xml_dumps
+from xml.dom.minidom import parseString as dom_parseString  # nosec B408
+from xml.etree.ElementTree import Element as XmlElement, tostring as xml_dumps  # nosec B405
 
 from ..schema import OutputFormat, SchemaVersion
 from ..schema.schema import (
@@ -80,7 +80,8 @@ def output_as_string(self, *,
                          indent: Optional[Union[int, str]] = None,
                          **kwargs: Any) -> str:
         self.generate()
-        return self._bom_xml if indent is None else dom_parseString(self._bom_xml).toprettyxml(
+        return self._bom_xml if indent is None else dom_parseString(  # nosecc B318
+            self._bom_xml).toprettyxml(
             indent=self.__make_indent(indent)
             # do not set `encoding` - this would convert result to binary, not string
         )
diff --git a/cyclonedx/serialization/__init__.py b/cyclonedx/serialization/__init__.py
index 7c5475866..720ee94d5 100644
--- a/cyclonedx/serialization/__init__.py
+++ b/cyclonedx/serialization/__init__.py
@@ -21,7 +21,7 @@
 from json import loads as json_loads
 from typing import TYPE_CHECKING, Any, Dict, List, Optional, Type
 from uuid import UUID
-from xml.etree.ElementTree import Element
+from xml.etree.ElementTree import Element  # nosec B405
 
 # See https://github.com/package-url/packageurl-python/issues/65
 from packageurl import PackageURL
diff --git a/cyclonedx/validation/xml.py b/cyclonedx/validation/xml.py
index cfa5ae813..f868f4ee9 100644
--- a/cyclonedx/validation/xml.py
+++ b/cyclonedx/validation/xml.py
@@ -29,7 +29,11 @@
 
 _missing_deps_error: Optional[Tuple[MissingOptionalDependencyException, ImportError]] = None
 try:
-    from lxml.etree import XMLParser, XMLSchema, fromstring as xml_fromstring  # type:ignore[import-untyped]
+    from lxml.etree import (  # type:ignore[import-untyped] # nosec B410
+        XMLParser,
+        XMLSchema,
+        fromstring as xml_fromstring,
+    )
 except ImportError as err:
     _missing_deps_error = MissingOptionalDependencyException(
         'This functionality requires optional dependencies.\n'
@@ -55,7 +59,9 @@ def validate_str(self, data: str) -> Optional[ValidationError]:
     else:
         def validate_str(self, data: str) -> Optional[ValidationError]:
             return self._validata_data(
-                xml_fromstring(bytes(data, encoding='utf8'), parser=self.__xml_parser))
+                xml_fromstring(  # nosec B320
+                    bytes(data, encoding='utf8'),
+                    parser=self.__xml_parser))
 
         def _validata_data(self, data: Any) -> Optional[ValidationError]:
             validator = self._validator  # may throw on error that MUST NOT be caught
diff --git a/pyproject.toml b/pyproject.toml
index 81d633513..ad12f7b88 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -87,6 +87,7 @@ autopep8 = "2.0.4"
 mypy = "1.6.1"
 tox = "4.11.3"
 xmldiff = "2.6.3"
+bandit = "1.7.5"
 
 [tool.semantic_release]
 # see https://python-semantic-release.readthedocs.io/en/latest/configuration.html
diff --git a/tools/schema-downloader.py b/tools/schema-downloader.py
index ca70f85e0..af0b11305 100644
--- a/tools/schema-downloader.py
+++ b/tools/schema-downloader.py
@@ -94,7 +94,7 @@
     for version in dspec['versions']:
         source = dspec['sourcePattern'].replace('%s', version)
         target = dspec['targetPattern'].replace('%s', version)
-        tempfile, _ = urlretrieve(source)
+        tempfile, _ = urlretrieve(source)  # nosec B310
         with open(tempfile, 'r') as tmpf:
             with open(target, 'w') as tarf:
                 text = tmpf.read()
@@ -105,4 +105,4 @@
                 tarf.write(text)
 
 for source, target in OTHER_DOWNLOADABLES:
-    urlretrieve(source, target)
+    urlretrieve(source, target)  # nosec B310
diff --git a/tox.ini b/tox.ini
index 56aa09d36..8187a2c18 100644
--- a/tox.ini
+++ b/tox.ini
@@ -9,6 +9,7 @@ envlist =
     flake8
     mypy-{current,lowest}
     py{312,311,310,39,38}-{allExtras,noExtras}
+    bandit
 skip_missing_interpreters = True
 usedevelop = False
 download = False
@@ -37,3 +38,9 @@ commands =
 [testenv:flake8]
 commands =
     poetry run flake8 cyclonedx/ tests/ typings/ examples/ tools/
+
+[testenv:bandit]
+commands =
+    poetry run bandit -c bandit.yml -v -r cyclonedx tests examples tools
+
+
