{"id":770,"date":"2026-09-08T04:01:03","date_gmt":"2026-09-08T04:01:03","guid":{"rendered":"https:\/\/networkyy.com\/automating-vulnerability-checks-with-python\/"},"modified":"2026-09-09T08:58:34","modified_gmt":"2026-09-09T08:58:34","slug":"automating-vulnerability-checks-with-python","status":"publish","type":"post","link":"https:\/\/networkyy.com\/fr\/automating-vulnerability-checks-with-python\/","title":{"rendered":"Automating Vulnerability Checks with Python"},"content":{"rendered":"<figure><img decoding=\"async\" src=\"https:\/\/images.pexels.com\/photos\/5380655\/pexels-photo-5380655.jpeg?auto=compress&#038;cs=tinysrgb&#038;dpr=2&#038;h=650&#038;w=940\" alt=\"Automating Vulnerability Checks with Python\" style=\"width:100%;height:auto;border-radius:8px;margin-bottom:24px;\" \/><figcaption>Photo by Tima Miroshnichenko on Pexels<\/figcaption><\/figure>\n<h1>Automating Vulnerability Checks with Python<\/h1>\n<p>In previous articles, we&#8217;ve explored API automation, file parsing, and system monitoring. Now we&#8217;re taking those skills into security territory\u2014specifically, automating vulnerability checks. This isn&#8217;t about reinventing Nessus or OpenVAS; it&#8217;s about building custom tooling that fits your infrastructure, automates repetitive security tasks, and integrates with your existing workflows.<\/p>\n<p>Security teams are drowning in manual checks: verifying package versions, cross-referencing CVE databases, scanning configuration files, and tracking remediation. Python gives us the power to automate these processes, create custom scanners tailored to our environment, and build early-warning systems that catch vulnerabilities before they&#8217;re exploited.<\/p>\n<h2>Table of Contents<\/h2>\n<ul>\n<li><a href=\"#why-automate\">Why Automate Vulnerability Checks<\/a><\/li>\n<li><a href=\"#cve-integration\">Integrating with CVE Databases<\/a><\/li>\n<li><a href=\"#dependency-scanning\">Automated Dependency Scanning<\/a><\/li>\n<li><a href=\"#configuration-checks\">Configuration Vulnerability Checks<\/a><\/li>\n<li><a href=\"#reporting-alerting\">Reporting and Alerting<\/a><\/li>\n<li><a href=\"#production-considerations\">Production Considerations<\/a><\/li>\n<\/ul>\n<h2 id=\"why-automate\">Why Automate Vulnerability Checks<\/h2>\n<p>Manual vulnerability management doesn&#8217;t scale. When you&#8217;re managing dozens of servers, hundreds of containers, or thousands of dependencies, manual checks become impossible. Automation provides consistency, speed, and the ability to run checks continuously rather than quarterly.<\/p>\n<p>Python excels here because it integrates easily with existing security tools, parses virtually any data format, and has robust libraries for network operations, data analysis, and API integration. You&#8217;re not replacing your security stack\u2014you&#8217;re making it smarter and more responsive.<\/p>\n<h2 id=\"cve-integration\">Integrating with CVE Databases<\/h2>\n<p>The National Vulnerability Database (NVD) provides a JSON API for CVE lookups. Let&#8217;s build a function that queries this API, caches results locally, and returns structured vulnerability data. This is the foundation for more complex scanning tools.<\/p>\n<p>For those looking to deepen their security automation knowledge, <a href=\"https:\/\/imp.i384100.net\/zxbRDr\" target=\"_blank\" rel=\"nofollow sponsored noopener\">Coursera<\/a> offers comprehensive cybersecurity and Python programming tracks that pair well with hands-on projects like this.<\/p>\n<pre><code>import requests\nimport json\nimport time\nfrom datetime import datetime, timedelta\nfrom pathlib import Path\n\nclass CVEChecker:\n    def __init__(self, cache_dir='cve_cache'):\n        self.base_url = 'https:\/\/services.nvd.nist.gov\/rest\/json\/cves\/2.0'\n        self.cache_dir = Path(cache_dir)\n        self.cache_dir.mkdir(exist_ok=True)\n        self.rate_limit_delay = 6  # NVD requires 6 seconds between requests without API key\n        \n    def get_cve_details(self, cve_id):\n        \"\"\"Fetch CVE details with local caching\"\"\"\n        cache_file = self.cache_dir \/ f\"{cve_id}.json\"\n        \n        # Check cache first\n        if cache_file.exists():\n            cache_age = datetime.now() - datetime.fromtimestamp(cache_file.stat().st_mtime)\n            if cache_age < timedelta(days=7):\n                with open(cache_file, 'r') as f:\n                    return json.load(f)\n        \n        # Fetch from API\n        try:\n            time.sleep(self.rate_limit_delay)\n            response = requests.get(f'{self.base_url}?cveId={cve_id}', timeout=10)\n            response.raise_for_status()\n            data = response.json()\n            \n            # Cache the result\n            with open(cache_file, 'w') as f:\n                json.dump(data, f, indent=2)\n            \n            return data\n        except requests.exceptions.RequestException as e:\n            print(f\"Error fetching {cve_id}: {e}\")\n            return None\n    \n    def parse_cve_severity(self, cve_data):\n        \"\"\"Extract CVSS score and severity\"\"\"\n        if not cve_data or 'vulnerabilities' not in cve_data:\n            return None\n        \n        try:\n            vuln = cve_data['vulnerabilities'][0]['cve']\n            metrics = vuln.get('metrics', {})\n            \n            # Try CVSS v3.1 first, fall back to v2\n            if 'cvssMetricV31' in metrics:\n                cvss = metrics['cvssMetricV31'][0]['cvssData']\n                return {\n                    'score': cvss['baseScore'],\n                    'severity': cvss['baseSeverity'],\n                    'vector': cvss['vectorString']\n                }\n            elif 'cvssMetricV2' in metrics:\n                cvss = metrics['cvssMetricV2'][0]['cvssData']\n                return {\n                    'score': cvss['baseScore'],\n                    'severity': cvss.get('baseSeverity', 'UNKNOWN'),\n                    'vector': cvss['vectorString']\n                }\n        except (KeyError, IndexError) as e:\n            print(f\"Error parsing CVE data: {e}\")\n        \n        return None\n\n# Example usage\nchecker = CVEChecker()\ncve_data = checker.get_cve_details('CVE-2023-44487')\nif cve_data:\n    severity = checker.parse_cve_severity(cve_data)\n    if severity:\n        print(f\"Score: {severity['score']}, Severity: {severity['severity']}\")\n<\/code><\/pre>\n<p>This class handles rate limiting, caching, and error handling\u2014all critical for production use. The cache prevents hammering the NVD API and speeds up repeated checks dramatically.<\/p>\n<h2 id=\"dependency-scanning\">Automated Dependency Scanning<\/h2>\n<p>One of the most common vulnerability vectors is outdated dependencies. Let's build a scanner that reads Python requirements files, checks versions against known vulnerabilities, and generates actionable reports.<\/p>\n<p>If you're building your skills in data manipulation and API integration, platforms like <a href=\"https:\/\/datacamp.pxf.io\/YR9dQK\" target=\"_blank\" rel=\"nofollow sponsored noopener\">DataCamp<\/a> offer interactive exercises that complement real-world automation projects perfectly.<\/p>\n<pre><code>import subprocess\nimport json\nfrom packaging import version as pkg_version\n\nclass DependencyScanner:\n    def __init__(self):\n        self.vulnerable_packages = []\n        \n    def get_installed_packages(self):\n        \"\"\"Get all installed packages with versions\"\"\"\n        result = subprocess.run(\n            ['pip', 'list', '--format=json'],\n            capture_output=True,\n            text=True\n        )\n        return json.loads(result.stdout)\n    \n    def check_package_vulnerability(self, package_name, package_version):\n        \"\"\"Check a package against the PyPI safety database\"\"\"\n        # Using PyPI's vulnerability API\n        try:\n            url = f'https:\/\/pypi.org\/pypi\/{package_name}\/json'\n            response = requests.get(url, timeout=5)\n            if response.status_code != 200:\n                return None\n            \n            data = response.json()\n            vulnerabilities = data.get('vulnerabilities', [])\n            \n            if not vulnerabilities:\n                return None\n            \n            # Check if current version is affected\n            affected = []\n            for vuln in vulnerabilities:\n                vuln_ranges = vuln.get('vulnerable_versions', [])\n                for vuln_range in vuln_ranges:\n                    if self.version_matches_range(package_version, vuln_range):\n                        affected.append({\n                            'id': vuln.get('id'),\n                            'summary': vuln.get('summary'),\n                            'fixed_in': vuln.get('fixed_in', [])\n                        })\n            \n            return affected if affected else None\n            \n        except Exception as e:\n            print(f\"Error checking {package_name}: {e}\")\n            return None\n    \n    def version_matches_range(self, current_version, vuln_range):\n        \"\"\"Simple version range checking\"\"\"\n        # This is simplified - production should use packaging.specifiers\n        try:\n            current = pkg_version.parse(current_version)\n            # Handle common patterns like \"<2.0.0\", \">=1.0,<1.5\"\n            if vuln_range.startswith('&lt;'):\n                max_ver = pkg_version.parse(vuln_range[1:])\n                return current < max_ver\n            return True  # Conservative: assume vulnerable if unsure\n        except:\n            return True\n    \n    def scan_environment(self):\n        \"\"\"Scan entire Python environment for vulnerabilities\"\"\"\n        packages = self.get_installed_packages()\n        results = {\n            'total_packages': len(packages),\n            'vulnerable_packages': [],\n            'scan_time': datetime.now().isoformat()\n        }\n        \n        for pkg in packages:\n            name = pkg['name']\n            ver = pkg['version']\n            \n            print(f\"Checking {name} {ver}...\")\n            vulns = self.check_package_vulnerability(name, ver)\n            \n            if vulns:\n                results['vulnerable_packages'].append({\n                    'package': name,\n                    'version': ver,\n                    'vulnerabilities': vulns\n                })\n        \n        return results\n    \n    def generate_report(self, results, output_file='vuln_report.json'):\n        \"\"\"Generate JSON report of findings\"\"\"\n        with open(output_file, 'w') as f:\n            json.dump(results, f, indent=2)\n        \n        # Print summary\n        vuln_count = len(results['vulnerable_packages'])\n        print(f\"\\n{'='*60}\")\n        print(f\"Scan complete: {vuln_count} vulnerable packages found\")\n        print(f\"Report saved to {output_file}\")\n        \n        if vuln_count > 0:\n            print(\"\\nVulnerable packages:\")\n            for pkg in results['vulnerable_packages']:\n                print(f\"  - {pkg['package']} {pkg['version']}: {len(pkg['vulnerabilities'])} CVEs\")\n\n# Run the scan\nscanner = DependencyScanner()\nscan_results = scanner.scan_environment()\nscanner.generate_report(scan_results)\n<\/code><\/pre>\n<h2 id=\"configuration-checks\">Configuration Vulnerability Checks<\/h2>\n<p>Beyond dependencies, misconfigurations are a major vulnerability source. Let's create a checker for common security misconfigurations in web server configs, SSH settings, and firewall rules.<\/p>\n<h3>SSH Configuration Auditing<\/h3>\n<p>This example scans SSH daemon configurations for common security weaknesses:<\/p>\n<pre><code>class SSHConfigChecker:\n    def __init__(self, config_path='\/etc\/ssh\/sshd_config'):\n        self.config_path = config_path\n        self.findings = []\n        \n    def parse_config(self):\n        \"\"\"Parse SSH config file into dict\"\"\"\n        config = {}\n        try:\n            with open(self.config_path, 'r') as f:\n                for line in f:\n                    line = line.strip()\n                    if line and not line.startswith('#'):\n                        parts = line.split(None, 1)\n                        if len(parts) == 2:\n                            config[parts[0].lower()] = parts[1]\n        except FileNotFoundError:\n            self.findings.append({\n                'severity': 'HIGH',\n                'issue': f'Config file not found: {self.config_path}'\n            })\n        return config\n    \n    def check_security_settings(self):\n        \"\"\"Check for common SSH security issues\"\"\"\n        config = self.parse_config()\n        \n        # Check root login\n        if config.get('permitrootlogin', 'yes').lower() != 'no':\n            self.findings.append({\n                'severity': 'HIGH',\n                'issue': 'Root login is permitted',\n                'recommendation': 'Set PermitRootLogin no'\n            })\n        \n        # Check password authentication\n        if config.get('passwordauthentication', 'yes').lower() != 'no':\n            self.findings.append({\n                'severity': 'MEDIUM',\n                'issue': 'Password authentication enabled',\n                'recommendation': 'Use key-based auth only'\n            })\n        \n        # Check protocol version\n        protocol = config.get('protocol', '2')\n        if '1' in protocol:\n            self.findings.append({\n                'severity': 'CRITICAL',\n                'issue': 'SSH Protocol 1 enabled',\n                'recommendation': 'Use Protocol 2 only'\n            })\n        \n        return self.findings\n<\/code><\/pre>\n<h2 id=\"reporting-alerting\">Reporting and Alerting<\/h2>\n<p>Detection without notification is useless. Integrate your vulnerability checks with alerting systems\u2014Slack, email, PagerDuty, or your ticketing system. Here's a simple Slack integration:<\/p>\n<pre><code>def send_slack_alert(webhook_url, findings):\n    \"\"\"Send vulnerability findings to Slack\"\"\"\n    critical = [f for f in findings if f.get('severity') == 'CRITICAL']\n    high = [f for f in findings if f.get('severity') == 'HIGH']\n    \n    color = '#ff0000' if critical else '#ff9900' if high else '#36a64f'\n    \n    message = {\n        'attachments': [{\n            'color': color,\n            'title': 'Vulnerability Scan Results',\n            'fields': [\n                {'title': 'Critical', 'value': str(len(critical)), 'short': True},\n                {'title': 'High', 'value': str(len(high)), 'short': True}\n            ],\n            'text': '\\n'.join([f\"\u2022 {f['issue']}\" for f in findings[:5]])\n        }]\n    }\n    \n    requests.post(webhook_url, json=message)\n<\/code><\/pre>\n<div style=\"background:#f8f8f8;color:#555;padding:14px 18px;border-radius:8px;margin-top:32px;font-size:14px;line-height:1.6;\"><span style=\"color:#222;font-weight:600;\">Stay in the loop<\/span> \u2014 join 125,000+ IT professionals following Networkyy: <a href=\"https:\/\/www.instagram.com\/networkyy\" target=\"_blank\" style=\"color:#7c3aed;font-weight:600;text-decoration:none;\" rel=\"noopener\">Instagram<\/a> \u00b7 <a href=\"https:\/\/www.facebook.com\/ITnetworkyy\/\" target=\"_blank\" style=\"color:#7c3aed;font-weight:600;text-decoration:none;\" rel=\"noopener\">Facebook<\/a> \u00b7 <a href=\"https:\/\/www.threads.com\/@networkyy\" target=\"_blank\" style=\"color:#7c3aed;font-weight:600;text-decoration:none;\" rel=\"noopener\">Threads<\/a> \u00b7 <a href=\"https:\/\/medium.com\/@mattouchi6\" target=\"_blank\" style=\"color:#7c3aed;font-weight:600;text-decoration:none;\" rel=\"noopener\">Medium<\/a><\/div>\n<h2 id=\"production-considerations\">Production Considerations<\/h2>\n<p>Moving from prototype to production requires attention to several critical areas:<\/p>\n<h3>Rate Limiting and Caching<\/h3>\n<p>External APIs have rate limits. Implement exponential backoff, respect<\/p>","protected":false},"excerpt":{"rendered":"<p>Build production-ready Python tools to automate vulnerability scanning, integrate with CVE databases, and detect security issues before attackers do.<\/p>","protected":false},"author":2,"featured_media":769,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":"","_yoast_wpseo_title":"Automating Vulnerability Checks with Python - Networkyy","_yoast_wpseo_metadesc":"Build production-ready Python tools to automate vulnerability scanning, integrate with CVE databases, and detect security issues before attackers do.","_yoast_wpseo_focuskw":"Python vulnerability scanning","rank_math_title":"Automating Vulnerability Checks with Python - Networkyy","rank_math_description":"Build production-ready Python tools to automate vulnerability scanning, integrate with CVE databases, and detect security issues before attackers do.","rank_math_focus_keyword":"Python vulnerability scanning"},"categories":[11],"tags":[],"class_list":["post-770","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-python-automation"],"contentshake_article_id":"","brizy_media":[],"_links":{"self":[{"href":"https:\/\/networkyy.com\/fr\/wp-json\/wp\/v2\/posts\/770","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/networkyy.com\/fr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/networkyy.com\/fr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/networkyy.com\/fr\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/networkyy.com\/fr\/wp-json\/wp\/v2\/comments?post=770"}],"version-history":[{"count":1,"href":"https:\/\/networkyy.com\/fr\/wp-json\/wp\/v2\/posts\/770\/revisions"}],"predecessor-version":[{"id":790,"href":"https:\/\/networkyy.com\/fr\/wp-json\/wp\/v2\/posts\/770\/revisions\/790"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/networkyy.com\/fr\/wp-json\/wp\/v2\/media\/769"}],"wp:attachment":[{"href":"https:\/\/networkyy.com\/fr\/wp-json\/wp\/v2\/media?parent=770"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/networkyy.com\/fr\/wp-json\/wp\/v2\/categories?post=770"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/networkyy.com\/fr\/wp-json\/wp\/v2\/tags?post=770"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}