Somewhere in the back of your mind, you know that when you import a package, you’re invariably importing its vulnerabilities — and its dependencies’ vulnerabilities, as well. Traditionally, non-critical vulnerabilities in the development environment have rarely been of concern. But with an increasing rate of cyberattacks on development and test environments, organizations are beginning to take the security of their non-production environments as seriously as their production environments.
Python’s popularity has meant more and more use of Python, which in turn has meant more and more bugs and vulnerabilities being found. Simply put, increased usage results in more issues coming to light. Although many Python packages and tools are well-coded and well-maintained, and exhibit few or no issues, others are not so robust.
For example, SafetyDB cites the following known vulnerability counts:
- Django: 119
- Pillow: 46
- Plone: 38
- TensorFlow and TensorFlow-directml: 301
- Tutor: 21
- OpenSSL: 7 vulnerabilities discovered this year alone
While most of these vulnerabilities are often just the result of bugs/poor coding practices, given the rise in Python supply chain attacks, some may also be attributable to malicious actors inserting compromised code.
As a Python developer, you can’t always avoid using some packages — even when you know they’re vulnerable. For example, perhaps you want to train a deep learning model for a classification task. Without TensorFlow, you must create your algorithm from scratch, wasting time better spent improving your model.
Despite the mounting threat from these vulnerabilities, there are a number of steps developers should be taking in order to make your projects less susceptible, including:
- Using the latest package version
- Assessing known vulnerabilities’ severity, and understanding how they affect your product
- Employing package management tools to quickly resolve vulnerabilities.
Let’s break down these best practices to show how you can work more securely without derailing your sprint deliverables.
Start With A Secure Python Dev Environment
It’s best practice to start with a secure environment. Creating an environment that contains the latest stable versions of Python and required packages should be your first step whenever possible.
With Python, If the latest version is a minor release, it should be fine to use. Major releases are a different story, as there’s a higher chance of severe bugs, and vulnerabilities will be unknown. For these reasons, some organizations prefer to wait before adopting the most recent version. You should also be aware of the tradeoffs: gaining potentially improved security and features from the newest version means giving up the relative certainty that comes with the older version.
When it comes to packages, the best practice is to use signed components from legitimate sources. Installing components directly from public repositories can be risky since they are prebuilt but unsigned, meaning they may contain compromised code. In any case, always ensure you download external code from secure links.
If possible, It’s also safer to choose frequently-updated packages that offer quick bug fixes, as it’s less likely your project will be exposed to a vulnerability for long. Of course, that also means implementing best practices around how often you upgrade packages. Consider establishing a policy around how long you’re willing to wait for a new version versus patching.
Speaking of patching, consider deploying a virtual patch if you need to use an older version of a package with an unpatched vulnerability. And as your development progresses, make sure you remove packages and files that you don’t use.
Assessing the Severity of Known Vulnerabilities
Vulnerabilities are generally scored according to the Common Vulnerability Scoring System (CVSS) as either:
- Low (score = 0.1-3.9)
- Medium (score = 4.0-6.9)
- High (score = 7.0-8.9)
- Critical (score = 9.0-10)
But vulnerabilities that are scored the same don’t always pose the same threat. Some vulnerabilities are a result of code errors affecting the runtime, while others, like hidden backdoors, can compromise your project’s integrity. You should understand which type of vulnerability you’re facing.
To figure out how, and just how badly your project is affected, you’ll need to Investigate each vulnerability individually instead of making a judgment call based on the number of Common Vulnerabilities and Exposures (CVE) alone. Heavily-used packages like Django and TensorFlow tend to have a high vulnerability count because they’re employed in numerous use cases by a lot of users who notice and report problems quickly. The takeaway here is that substituting less popular packages just because they have a lower CVE count won’t necessarily make your product less vulnerable.
Once you know the vulnerabilities affecting your packages and have determined whether they will affect your product, you’ll need to determine how best to deal with them. Your organization likely already has a policy on remediating vulnerabilities, typically according to CVSS severity level and product risk.
But even if you can’t picture how known vulnerabilities may affect your use case, you should still proceed with caution.
Use Tooling to Manage Your Python Vulnerabilities
When it comes to vulnerabilities, there are dozens of third-party tools that can help an organization stay abreast of emerging threats by providing timely warnings, and even suggesting secure upgrade options. Typically, they offer the ability to:
- Be notified of reported vulnerabilities on platforms like CVE Details and the National Vulnerability Database (NVD).
- Understand the threat level of your Python dependencies.
- You must keep a consistently up-to-date inventory of every package and tool that you use, as well as their dependencies. This information should include both your client and server-side components and transitive dependencies.
- Understand whether patches or upgrade versions exist to resolve the threat.
But none of these tools provide the ability to remediate the vulnerability, rebuild your environment, test it and redeploy it. These are all necessary steps, but they’re very time and resource-intensive, which is why most organizations only ever address critical vulnerabilities.
ActiveState offers a cloud-based all-in-one package management solution that can help you gain overarching visibility into your project’s vulnerabilities, while innovatively managing your Python project’s packages and dependencies.
The ActiveState Platform automatically builds Python runtime environments from source code, including linked C and Fortran libraries (thereby providing enhanced security over installing prebuilt packages), and then checks all your dependencies (including transitive and shared dependencies) for vulnerabilities. If found, The ActiveState Platform will flag them within the product and notify you out-of-band by email.
But more importantly, it helps you quickly and easily remediate vulnerabilities, and automatically rebuild a secure version of your environment in minutes. You can then update each affected environment across dev, test and your CI/CD pipeline with a single command.
Conclusions: Automate Vulnerability Remediation to Stay Secure Without Giving up Speed
As more and more malicious actors target non-production environments, developers must learn to keep their development environments secure. But without automating vulnerability remediation, the production costs would be just too high.
Luckily, there are some quick and easy solutions you can employ to keep your projects secure:
- Work with the latest versions of Python and the packages you require
- Understand the vulnerabilities in your runtime environment, and how they affect your project
- Use package management tools like the ActiveState Platform to automatically remediate, rebuild and redeploy secure runtimes to your dev, test and CI/CD environments.