Recently, modern software development teams have been hearing a lot about securing the software supply chain. Breaches like SolarWinds and Codecov have demonstrated that attackers are interested in – and capable of – compromising software development infrastructure and damaging code integrity. They’ve also shown us how our modern, automated DevOps processes can help attackers access upstream and downstream environments once they gain that foothold. For example, attackers injected malware into the build process in the SolarWinds breach. This malware was able to work its way through the build process, testing, packaging, signing, and deployment phases to establish a backdoor in production environments in supposedly secure on-premises enclaves.
The fact that the malware was introduced via a trusted third-party contributor to the development process has focused attention on the software supply chain and how it’s becoming a popular target of attackers.
Modern software applications are exceptionally complex, with distributed architectures, microservices, hybrid topologies, and diverse dependencies spanning open-source, commercial, and proprietary code. The processes used to create and maintain these systems are even more complex since they need to juggle those aspects across multiple branches, versions, and environments. That’s a problem because higher complexity requires extensive effort to secure. Organizations need to address this problem now. In the report How Software Engineering Leaders Can Mitigate Software Supply Chain Security Risks, Gartner predicts that 45% of all organizations will experience attacks on their software supply chains by 2025.
So how can organizations protect against this type of code tampering? This post examines whether existing security approaches are sufficient to protect modern software pipelines and provides five straightforward steps that any organization can take to harden their pipelines to keep attackers out.
Do Existing Application Security Approaches Protect Code Integrity in Pipelines?
Traditional application security approaches such as SAST, DAST, and SCA evaluate individual applications at a point in time to determine whether they contain vulnerabilities that could be exploited. These determinations are made in the context of that particular application as it exists at that point in the development process and not as it will exist in the broader context of all apps and resources in the production environment.
Protecting code integrity, in contrast, requires following inputs through the development process to determine if they are processed correctly and completely. Tampering can happen even if no vulnerabilities are exploited. Perhaps the biggest difference from other types of application security is that while integrity must be protected in the context of the development process, it cannot focus on a specific application, tool, or phase. It must understand the history of the artifact in question across all phases of the SDLC, who acted upon it, how it was processed, as well as how it should have been processed.
Perhaps unsurprisingly, this requires a fundamentally different approach to security. In many ways, it requires you to push beyond the limitations of existing security and development practices to eliminate silos and harden the entire software development process and supply chain.
Ensuring Code Integrity Across the SDLC
We’ve identified five key steps for hardening your development process against code tampering:
Harden SDLC Tools, Configurations, Privileges
It’s important to build a foundation of trust in your development process so that you know what is happening and who is responsible for each action. Requiring strong authentication is a good start, and it must be consistently enforced across all of the repositories and tools used in your SDLC. That can be a tall order given that each project might use different tools, and there may be many different identity authorities in large organizations or environments that allow external contributors.
Identity policy is just one aspect of governance policy, and your trust in the development process will correlate to your ability to govern development according to that policy. Define a governance policy that ensures all stakeholders are aware of regulatory needs and performance goals. Enforce this policy by establishing controls such as mandatory MFA with automated configuration audits, regular permissions reviews based on least privilege principles, and logging activity through all phases of the SDLC to monitor compliance to that policy. The policy and related controls are themselves part of the development process, so ensure that the controls allow for monitoring of their own configuration and use.
Validate Integrity in Every Step of the SDLC
Now that you have confidence that you know what is happening and who is responsible, you can establish controls that validate integrity at every step of the SDLC. Validate that commits and pull requests only trigger automated actions when the submitter is a trusted user. Verify inputs into all pipeline steps, for example, by ensuring that the code to be built was pulled from a trusted commit, or that components that are being packaged into a container have correct checksums.
Validate that the input to build steps matches the output of earlier steps, and do comparable validation during other handshakes. Maintain a record of all of these events and activities so that you can document the chain of custody for each artifact. Integrity is not only about verifying a lack of violations; you also need to verify that all necessary steps were performed.
Prevent Tampering of Critical Code and Configurations
Certain parts of the development process can be considered critical. This includes the policy configurations and controls that monitor and validate compliance as well as the infrastructure as code that provisions the development, testing, and production environments. These parts should be monitored and controlled with an extra level of scrutiny to ensure that no accidental or malicious changes will weaken the foundation of trust.
Monitor Suspicious, Anomalous Behavior
If an attacker gains access to an authorized user’s credentials or valid keys, they have the ability to do anything those credentials enable them to do. That’s a strong argument for using the principle of least privilege to minimize the damage that leaked credentials can do.
The foundation of trust and governance established in steps 1 through 3 provide a mechanism for understanding the normal and intended development behavior. With that detailed knowledge of the SDLC, you can focus scrutiny on anomalous activity. If an account suddenly starts accessing new repositories or violating development standards, you may want to rein in its permissions until you can determine if the account is compromised. This would be impossible if strong governance were not in place.
Govern Code Integrity Across the Entire SDLC
With these pieces in place, you have strong governance, hardened configurations, and visibility into the code, users, and events that happen throughout the development process. You have the means to detect tampering, such as foreign code or artifacts being injected into the development pipelines, and even to detect anomalous activity that might represent a threat.
In order to act upon those findings, you need to understand the full context around what has happened. Do the findings represent violations of the governance policy? Will they lead to violations or to increased risks downstream? What activity happened to these resources prior to the finding? Are there other suspicious events related to the finding?
It’s important to understand the full context of a finding throughout the related component’s entire history and across all the dimensions of risk, such as secrets management, infrastructure security, code exposure and leakage, application vulnerabilities, and much more, in order to properly assess the risk, the finding represents. Multiple suspicious indications will increase confidence in the likelihood of a finding requiring action such as preventing deployment.
Without that complete understanding of the history and dimensions of risk, you will not be able to protect code integrity effectively.
Learn How Cycode Helps You Protect Code Integrity
Modern software architectures and development processes are exceptionally complex and have an expansive attack surface. Moreover, automated DevOps processes are making it easier than ever for attackers to gain access to all parts of the development process. Attackers and regulators are increasingly focused on these risks, making it a critical priority for any organization that develops software.
Cycode offers the only software supply chain security solution capable of breaking down silos and effectively preventing code tampering across all phases of your SDLC and all of your environments. Our Knowledge Graph provides visibility into all of the tools, users, activities, and events across your entire SDLC to provide a holistic view of security risk. Schedule a demo or browse our website to see how easy it is to secure your software supply chain with Cycode.