Secure guardrails represent a different approach to security. Rather than a security “gate” that halts progress for inspection, guardrails nudge high-speed developers back towards the “paved road” – a path that is secure by default. For example, “We recommend you use this library for YAML parsing, because its default behavior doesn't trust any user input, and therefore it's not vulnerable to any deserialization attacks.”
This post illustrates some of the technical aspects of secure guardrails and the characteristics we think are essential to successfully integrating them into an AppSec program. Spoiler alert: the developer experience (DevX) is paramount.
For more background on why we think secure guardrails are critical to the future of AppSec, see this blog post from our CEO, Isaac.
Essential components of secure guardrails
Secure guardrails guide developers to write secure code through real-time security feedback early in development—in the editor, at commit-time, and during code reviews.
They nudge developers back to secure code with inline remediations if they deviate from an industry-standard/organization-specific "paved road."
With secure guardrails, developers don’t need deep security knowledge to write secure code and spend less time dealing with recurring vulnerabilities
In essence, a secure guardrail nudges a developer to get back on the path of secure coding, and it must include a when and a where, then a what.
Interface: the when and where
The when: it’s critical that the nudge is timely! If a skier is about to go off piste, they need to be warned about entering a dangerous slope when they still have time to adjust their path, in case they want to avoid the higher risk area. In the case of software, this could be when code is written, saved, committed, or pushed for review.
The where: in addition to being valuable and timely, the nudge must appear in view of the intended audience. For secure guardrails, this means appearing always in the developer workflow —perhaps in the editor, on the command line, or during code review (PR comments)—and never in a workflow or in software designed for the security team.
Contents: the what
The what: this is the contents of the nudge, the core message that informs the developer they are about to go off piste — it’s possible to keep going, but it’s a much more dangerous path. It should also include contextual advice on what to do (instead of only what not to do), and also instructions on how to change the code. That guidance should be in the context of the security policies and best practices of the organization or even the developer’s team.
Both interface and contents are essential. If either component is absent, the effectiveness of the guardrail is significantly reduced. In fact, we shouldn’t even consider this case to be a guardrail.
Secure guardrail example
Consider the following example of a secure guardrail with FlaskWTF (an integration of Flask and WTForms). When creating views that don’t use FlaskForm or make AJAX requests, developers don’t automatically get CSRF (cross-site request forgery) protection. If the application uses cookie-based authentication, an attacker can trick users into sending authenticated HTTP requests without their knowledge from any arbitrary domain they visit.
This Semgrep rule determines if WTF_CSRF_CHECK_DEFAULT
is set to False
and if so, warns the developer to ensure it’s intentional, because in this case the CSRF protections no longer happen automatically, even though the CSRF tokens are still embedded and included. That means developers would need to remember to secure their requests on every instantiation, which requires developer discipline and knowledge, and increases the chance of human error.
This rule is most effective as a secure guardrail, if the message is shown to the developer in a timely manner and in the developer workflow. Otherwise the result is seen only by the security team, who then have to determine if the developer has added protections manually to their code, or they must put the issue into their backlog.
The guardrail shown to the developer during code review includes a recommended code fix that can be applied to the PR directly.
To supplement the fix shown above, Semgrep Assistant uses AI to provide step-by-step instructions that make it easy to understand the validity of the suggested fix.
Implementing secure guardrails can slow the growth of the vulnerability backlog and help prevent security issues from appearing in the first place, which is critical to AppSec teams struggling to keep up with an ever-growing backlog.
Preventing issues by construction with secure defaults
Going beyond secure guardrails that prevent developers from shipping insecure code, secure defaults guide them back towards the paved, secure road. They prevent issues by construction.
Secure defaults are inherently secure libraries, frameworks, configurations, or settings. They mitigate common security concerns and minimize the need for developers to manually implement security measures. They also reduce the risk of vulnerabilities due to human error, and eliminate entire classes of vulnerabilities by construction—thus maintaining robust security with minimal developer effort.
In the CSRF example above, the Semgrep rule can be used to apply a secure default. In this case, the secure default involves setting WTF_CSRF_CHECK_DEFAULT
to True
. This turns on the built-in CSRF protections, and doing so no longer requires the developer to remember to call csrf.protect()
each time before handling requests.
Your team’s personalized security guidance
To get the most out of guardrails, it’s important to go beyond widely-applicable security guidance and apply guardrails in the context of the specific organization or project at hand. AppSec teams sometimes need to give that very specific, personalized remediation guidance to developers. Examples of such cases include:
specifying an attribute of the organization to save manual work in implementing the fix, such as an AWS account ID
specifying a secure default, company standard way to fix a class of vulnerability, such as using AWS Secrets Manager
expressing stylistic preferences, such as displaying the remediation instructions in a language other than English
Semgrep Assistant Memories allows teams to tailor remediation guidance to their organization's standards and defaults on a per-project, per-rule basis. In place of a general (but still feasible) AI-generated fix, teams can enter their own custom instructions, and Assistant will provide all remediation guidance for that project and Semgrep rule following the instructions saved in the Memory.
Here’s a short screencast showing an overview of Semgrep Memories: