One of the methods used for developing secure applications is frequently testing the code for security bugs through a process known as code review. Code reviews consist of looking at the source code of an application to search for possible vulnerabilities using a white box approach. By having access to the code, the reviewer can guarantee a greater coverage of the application's functionalities and lower the time required to find bugs.
If left unattended, vulnerabilities introduced early in the development process will propagate to the end of a project, where resolution is more laborious and costly. Code reviews will attempt to detect such vulnerabilities early when they are easier to fix.

Manual vs Automated Code Review
Code reviews are often done through a combination of manual analysis and automated tools for the best results. Both approaches have advantages that need to be considered when deciding what is best at each stage of the development lifecycle.
On the one hand, manual code reviews have the advantage of a human evaluating the code, which allows for a thorough analysis and more precise results. However, since an application often has thousands and thousands of lines of code, the task can quickly become overwhelming for the reviewer, leading to some vulnerabilities being missed because of fatigue.
On the other hand, automated tools excel at finding common vulnerabilities almost instantly, saving loads of time to the reviewer. Automated tools will also perform consistently, no matter the size of the code base, so they won't miss vulnerabilities as a human could do, as long as they have predefined rules to match them. If the tool has no rules configured for a specific type of vulnerability, they are likely to miss those.
Another important aspect to compare is cost. The cost of a manual review will often be higher, as a reviewer must spend lots of time tracing vulnerabilities through the code. Automated tools will perform their analysis almost instantly.
For these reasons, you will typically want to run automated tests early in the development lifecycle to take care of all the low-hanging fruits with lower costs and have manual reviews spaced periodically or when important project goals are met to take care of complex vulnerabilities that the automated tools may not be able to detect.
Questions:
Are automated code reviews a substitute for manual reviewing? (yea/nay)
— — —
What type of code review will run faster? (Manual/Automated)
— — — — -
What type of code review will be more thorough? (Manual/Automated)
— — —
Task 3 Manual Code Review
Before jumping into SAST tools, we will look at how manual core reviewing is usually performed, as this will make it easier to understand how SAST tools look at code.
During this task, our goal will be to find SQL injection vulnerabilities in the source code of a simple application. The application has other vulnerabilities, but we will focus on a single type of vulnerability to understand how traditional code reviews are done and how those steps map to the analysis techniques used by SAST tools.
Before continuing, make sure your VM is running by pressing the green Start Machine button attached to this task. The VM is starting in split view. In case the machine is not visible, press the blue Show Split View button at the top right of this room.
For this task, the code we will be using can be found in /home/ubuntu/Desktop/simple-webapp/
Searching for Insecure Functions
The first step when reviewing code is identifying potentially insecure functions in use. Since we are looking for SQL injections, we should focus on any functions that could be used to send raw queries to the database. Since our code uses PHP and MySQL, here are some functions that are typically used to send MySQL queries:
Database EngineFunctionMySQLmysqli_query() mysql_query() mysqli_prepare() query() prepare()
A straightforward way to manually search instances of such functions is to use grep to check all of our project's files recursively. For example, to search for instances of mysqli_query(), go to the project's base directory and run the following command:
Linux
user@machine$ cd /home/ubuntu/Desktop/simple-webapp/html/
user@machine$ grep -r -n 'mysqli_query('
db.php:18: $result = mysqli_query($conn, $query);The -r option tells grep to recursively search all files under the current directory, and the -n option indicates that we want grep to tell us the number of the line where the pattern was found. In the above terminal output, we can see that a single instance of mysqli_query() was found on line 18.
We have identified a line that could lead to SQL injections. However, just by looking at that line, we can't determine whether a vulnerability is present.
Understanding the Context
Let's open db.php to analyse the context around the mysqli_query() function to see if we get a better idea of how it is used:
function db_query($conn, $query){
$result = mysqli_query($conn, $query);
return $result;
}Here we can see that mysqli_query() is wrapped into the db_query() function, and that the $query parameter is passed directly without modification. It is very common for functions to be nested into other functions, so simply analysing the local context of a function is sometimes not enough to determine if a vulnerability is present. We now need to trace the uses of the db_query() function throughout our code to identify potential vulnerabilities.
Tracing User Inputs to Potentially Vulnerable Functions
We can use grep again to search for uses of db_query():
Linux
user@machine$ grep -rn 'db_query('
hidden-panel.php:7:$result = db_query($conn, $sql);
hidden-panel.php:20:$result2 = db_query($conn, $sql2);
hidden-panel.php:23:$result3 = db_query($conn, $sql3);
db.php:17:function db_query($conn, $query){Here we get three uses for db_query() on hidden-panel.php. Once again, we can analyse the context of each call, starting with the call on line 7:
$sql = "SELECT id, firstname, lastname FROM MyGuests WHERE id=".$_GET['guest_id'];
$result = db_query($conn, $sql);Congrats on finding an SQL injection! Whatever is passed in the guest_id parameter via the GET method will be concatenated to a raw SQL query without any input sanitisation, enabling the attacker to change the query.
If we do a similar process for the other two uses of db_query(), we will have the following code:
$sql2 = "SELECT id, logtext FROM logs WHERE id='".preg_replace('/[^a-z0-9A-Z"]/', "", $_GET['log_id']). "'";
$result2 = db_query($conn, $sql2);
$sql3 = "SELECT id, name FROM asciiart WHERE id=".preg_replace("/[^0-9]/", "", $_GET['art_id'], 1);
$result3 = db_query($conn, $sql3);Again, we have some GET parameters being concatenated into SQL queries. This would give us the impression that we have two more vulnerabilities identified. Still, in both cases, the GET parameters are sanitised through preg_replace() using different regular expressions to replace any character that isn't allowed with an empty string. To decide if these lines of code are vulnerable, we will need to evaluate if the filters in place allow SQL injections to pass.
The query on $sql2 is passed through a filter that only allows characters that are either alphanumeric or double-quotes. While double-quotes may seem like a possible vector for SQLi, they don't pose a threat in this case since the SQL sentence encloses the string passed through $_GET['log_id'] between single-quotes ('). Since an attacker would have no way to escape from the string in the SQL sentence, we can be sure that this line isn't vulnerable.
The query on $sql3 is even more restrictive, allowing only numeric characters to be passed through $_GET['art_id']. However, notice that the preg_replace() function is called with a third parameter set to "1". If we refer to the manual page of the function(opens in new tab), we will learn that the third parameter indicates the maximum number of replacements to be done. Since it is set to 1, only the first character that isn't a number will be replaced with an empty string. Any other characters will pass without being replaced, enabling SQL injections. This line is indeed vulnerable.
Enough Manual Reviewing
We have used manual code reviewing to identify two SQL injection points in our application. While the example application is quite straightforward, a real application has many more lines of code. Tracing each instance of a potentially vulnerable function will be way more complicated. By now, it should be evident that manually reviewing large code bases can quickly become a tedious task. We will now move onto using SAST tools to perform the same analysis for us and analyse how well they perform.
Bonus Exercise
Use manual code reviewing to find other types of vulnerabilities in the provided project. The following questions will guide you through it.
Questions
Local File Inclusion (LFI) attacks are made possible by the misuse of one of the following functions in PHP:
require()include()require_once()include_once()
Answer the following questions using grep to search for LFI vulnerabilities only on the .php files in the html/ directory of the simple-webapp project.
No answer needed.
Which of the mentioned functions is used in the project? (Include the parenthesis at the end of the function name)
Hint: use these commands cd /home/ubuntu/Desktop/simple-webapp/html/. Then, try running the command: grep -rn --include=*.php 'include(' .
How many instances of the function found in question 2 exist in your project's code?
Hint: Count the .php files that pop up.
Only one of the function's instances is vulnerable to LFI. Remember that for LFI to be present, the attacker must be able to manipulate a part of what is sent to the vulnerable function. The vulnerable instance must contain some reference to a GET or POST parameter or other manipulable inputs.
What file contains the vulnerable instance?
Look for anything that has $_GET['img']);
What line in the file found on the previous question is vulnerable to LFI?
Hint: check the green number.
Task 4: Automated Code Review
Static Application Security Testing (SAST) refers to using automated tools for code analysis. The idea is not to replace manual code reviews but to provide a simple method to automate simple code checks to quickly find vulnerabilities during the development process without requiring a specialised individual.
SAST complements other techniques, such as Dynamic Application Security Testing (DAST) or Software Composition Analysis (SCA), to provide a holistic approach to application security during the development lifecycle. Just as with any of the other techniques, SAST will have its pros and cons that we need to be aware of:
Pros:
- It doesn't require a running instance of the target application.
- It provides great coverage of the application's functionality.
- It runs fast as opposed to other dynamic techniques.
- SAST tools report exactly where vulnerabilities are in the code.
- Easy to integrate into your CI/CD pipeline.
Cons:
- The source code of an application is not always available (third-party apps).
- Prone to false positives.
- Can't identify vulnerabilities that are dynamic in nature.
- SAST tools are mostly language-specific. They can only check languages they know.
SAST Under the Hood
While every SAST tool is different, most of them will perform two main tasks:
- Transform the code into an abstract model: SAST tools usually ingest the source code and produce an abstract representation for further analysis. Most SAST tools will represent the code using Abstract Syntax Trees (AST), but some tools may have other equivalent proprietary structures. This allows for easier code analysis in a way that is independent of the programming language in use. This step is crucial for later analysis, as any feature of a programming language that isn't correctly translated into the AST will probably not be analysed for security issues effectively.
- Analyse the abstract model for security issues: Different analysis techniques will be used to search for potential vulnerabilities in the code model.
During this room, we won't cover code modelling in detail, as you won't have to deal with it from a user's perspective. We will instead focus on the different analysis techniques commonly used by SAST tools:

Semantic analysis: This type of analysis can be compared to grepping for potentially insecure functions while doing manual code reviews. It aims to find flaws concerning the use of potentially insecure code in a localised context.
Examples of this include searching for calls to mysqli_query() where GET or POST parameters are directly concatenated into the query string:
mysqli_query($db, "SELECT * from users where username=".$_GET['username'])
Dataflow analysis: There are situations where potentially dangerous functions are in use, but it isn't clear whether or not a vulnerability is present just by analysing the local context around the function call. Take, for example, a function defined as follows:
function db_query($conn, $query){
$result = mysqli_query($conn, $query);
return $result;
}By looking at the function's code, it's hard to say if there are any vulnerabilities. Analysing the local context of the call to a dangerous function is not enough in this case.
Dataflow analysis will trace how information flows from inputs the user can manipulate to potentially vulnerable functions, just as we did when manually analysing the provided application's code. In dataflow analysis terminology, data inputs will be referred to as sources, and potentially vulnerable functions will be referred to as sinks. If data flows from a source to a sink without sanitisation, we have a vulnerability.
Going back to the db_query() function, dataflow analysis would have to find all of its usages and trace back to see if any tainted input (the source) is sent to it, finally ending up as part of the query executed by mysqli_query() (the sink).


Control flow analysis: Analyses the order of operations in the code in search for race conditions, use of uninitialised variables or resource leaks. As an example, look at the following piece of Java code:
String cmd = System.getProperty("cmd");
cmd = cmd.trim();If the cmd property isn't defined, the call to System.getProperty() will return NULL. Calling the trim method from a NULL variable will throw an exception on runtime.

Structural analysis: Analyses specific code structures of each programming language. This includes following best practices when declaring classes, evaluating code blocks that may never execute (dead code), correctly using try/catch blocks and other issues related to using insecure cryptographic material (weak keys or IVs).
Here's a quick example of code that would be detected by structural analysis:
$options = array('private_key_bits' => 1024, 'private_key_type' => OPENSSL_KEYTYPE_RSA);
$res = openssl_pkey_new($options);In this case, we have an implementation of RSA with a key size of 1024, considered insufficient by today's standards.

Configuration analysis: Searches for application configuration flaws rather than the code itself. As an example, applications running under Internet Information Services will have a configuration file called web.config, PHP will hold all of its configuration options in a file called php.ini, and most applications will use some configuration file. By checking configurations, the tool will identify possible improvements.
Here's an example of two configuration directives in PHP that would probably raise an alert on SAST tools, as they facilitate some attack vectors for RFI, SSRF or other:
allow_url_include = On
allow_url_fopen = OnIt is important to note that not every SAST tool will implement all the analysis techniques we discussed, but it is good to have them as a reference to compare different solutions out there.
Answer the questions below
Does SAST require a running instance of the application for analysis? (yea/nay)
What kind of analysis would likely flag dead code segments?
Hint: evaluating code blocks that may never execute (dead code)
What kind of analysis would likely detect flaws in configuration files?
Hint: Pretty self-explanatory there.
What kind of analysis is similar to grepping the code in search of flaws?
Hint: This type of analysis can be compared to grepping for potentially insecure functions while doing manual code reviews.
Task 5: Rechecking our application with the SAST Tool.
Now that we know how SAST tools work, we are ready to use a couple of them. We will use a simple PHP application as our target for this task. You can find the application's code in the simple-webapp folder on your desktop.
Rechecking our Application with Psalm
We will first use Psalm (PHP Static Analysis Linting Machine), a simple tool for analysing PHP code. The tool is already installed as part of the application's project, so you won't need to install it, but you can find installation instructions on Psalm's online documentation(opens in new tab) if required.
Open a terminal and go to the project's directory. You will find a psalm.xml file at the root of the project. This is Psalm's configuration file, and it should look like this:
<?xml version="1.0"?>
<psalm
errorLevel="3"
resolveFromConfigFile="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
findUnusedBaselineEntry="true"
>
<projectFiles>
<directory name="html/" />
<ignoreFiles>
<directory name="vendor" />
</ignoreFiles>
</projectFiles>
</psalm>We won't go too deep into the configuration options, but here you can see the errorLevel parameter, which indicates how strict Psalm will be when reporting issues. The lower the value, the more issues will be reported. There's also a section called projectFiles, where the files to be scanned are indicated. Only the html directory will be scanned for this project, and the vendor directory will be ignored (as we don't want to test third-party dependencies).
With the configuration file set, you can run Psalm using the following command from within the project's directory:
Linux
user@machine$ cd /home/ubuntu/Desktop/simple-webapp/
user@machine$ ./vendor/bin/psalm --no-cache
ERROR: TypeDoesNotContainType - html/hidden-panel.php:10:5 - Operand of type 0 is always falsy (see https://psalm.dev/056)
if ($result->num_rows = 0) {By default, Psalm will only run some structural analysis over the code and show us programming errors that need our attention. In the previous example, Psalm reports that the condition on the if clause is always false. In this case, the programmer mistakenly used the assignment operator (=) instead of the comparison operator (==). Since the assignment operator always returns the assigned value (0 in this case), the condition will always evaluate as false (0 will be automatically cast to false in PHP).
The default tests will search for issues with variable types, variable initialisation and other safe coding patterns. While these issues are not vulnerabilities, Psalm will make recommendations so your code follows coding best practices, which is a good start to avoid runtime errors.
Psalm also offers the possibility to run dataflow analysis on our code using the --taint-analysis flag. The output for this command will be much more interesting as it will pinpoint possible security issues. The output of the command will look like this:
Linux
user@machine$ cd /home/ubuntu/Desktop/simple-webapp/
user@machine$ ./vendor/bin/psalm --no-cache --taint-analysis
ERROR: TaintedInclude - html/view.php:22:9 - Detected tainted code passed to include or similar (see https://psalm.dev/251)
$_GET
<no known location>
$_GET['img'] - html/view.php:22:28
include('./gallery-files/'.$_GET['img']);
concat - html/view.php:22:9
include('./gallery-files/'.$_GET['img']);For each error reported, Psalm will show you a complete trace of the data flow from the source ($_GET) to the sink function (include()). Here we have a typical Local File Inclusion (LFI) vulnerability, as the GET parameter img is concatenated directly into the filename passed to the include() function.
Dataflow analysis usually gets the most interesting findings from a security standpoint. However, other structural findings are equally important to fix, even if they don't directly translate into an exploitable vulnerability. Structural flaws can often lead to business logic errors that may be hard to track or some unpredictable behaviours in your app.
Dealing With False Positives and False Negatives
No matter what SAST tool you use, errors will always be present. Just as a quick reminder, we will generally be concerned with the two following error types:
- False positives: The tool reports on a vulnerability that isn't present in the code.
- False negatives: The tool doesn't report a vulnerability that is present in the code.
These errors might present themselves because the tool cannot correctly assess the target code, but they can also be introduced if we, as users, don't use the tool correctly.
As a quick example, when we manually reviewed the code before, we found three possible instances of SQL injection. Still, we discarded one of them as character filtering was being applied to it effectively, leaving us with two confirmed SQL injection vulnerabilities. If we check Psalm's output, we will notice only a single instance of SQL injection is reported (the first one in lines 6-7 of hidden-panel.php):
Linux
user@machine$ ./vendor/bin/psalm --no-cache --taint-analysis
ERROR: TaintedSql - html/db.php:18:32 - Detected tainted SQL (see https://psalm.dev/244)
$_GET
<no known location>
$_GET['guest_id'] - html/hidden-panel.php:6:65
$sql = "SELECT id, firstname, lastname FROM MyGuests WHERE id=".$_GET['guest_id'];
concat - html/hidden-panel.php:6:8
$sql = "SELECT id, firstname, lastname FROM MyGuests WHERE id=".$_GET['guest_id'];Just as an experiment, let's comment out lines 6 and 7 in hidden-pannel.php and see what happens:
// $sql = "SELECT id, firstname, lastname FROM MyGuests WHERE id=".$_GET['guest_id'];
// $result = db_query($conn, $sql);In theory, we should have no more errors reporting TaintedSQL instances. However, if we execute Psalm once again, it will now report a different TaintedSQL error corresponding to one of the other two SQL queries:
Linux
user@machine$ ./vendor/bin/psalm --no-cache --taint-analysis
ERROR: TaintedSql - html/db.php:18:32 - Detected tainted SQL (see https://psalm.dev/244)
$_GET
<no known location>
$_GET['log_id'] - html/hidden-panel.php:19:87
$sql2 = "SELECT id, logtext FROM logs WHERE id='".preg_replace('/[^a-z0-9A-Z"]/', "", $_GET['log_id']). "'";
call to preg_replace - html/hidden-panel.php:19:87
$sql2 = "SELECT id, logtext FROM logs WHERE id='".preg_replace('/[^a-z0-9A-Z"]/', "", $_GET['log_id']). "'";By now, you are probably wondering why Psalm didn't detect this vulnerability the first time. The reason for this can be found if you check the first line of both errors. Both show line 18 of db.php as the source of the problem. For Psalm, both vulnerabilities are the same and related to how you call mysqli_query() on line 18 of db.php. In other words, Psalm expects you to apply a fix there, as it doesn't understand that the code defines db_query() as a wrapper to any database queries.
Before continuing, make sure to uncomment back lines 6-7 in hidden-panel.php:
$sql = "SELECT id, firstname, lastname FROM MyGuests WHERE id=".$_GET['guest_id'];
$result = db_query($conn, $sql);To better help Psalm understand the situation, we can use some annotations to give more context. We can specify that db_query() should be considered a sink, so we get an error if any tainted input reaches the function via the $query parameter. To do so, add the following comment on top of the db_query() function definition in db.php:
/**
* @psalm-taint-sink sql $query
* @psalm-taint-specialize
*/
function db_query($conn, $query){
$result = mysqli_query($conn, $query);
return $result;
}The @psalm-taint-sink annotation tells Psalm to check the $query parameter for tainted inputs of type sql. Now Psalm will issue a TaintedSQL error every time a tainted input reaches db_query().
We also need to add the @psalm-taint-specialize annotation to tell Psalm that each invocation of the function should be treated as a separate issue and that the function's taintedness depends entirely on the inputs it receives. This way, we will get both issues separately.
After re-running Psalm, we should now get all instances of TaintedSQL errors as expected:
Linux
user@machine$ ./vendor/bin/psalm --no-cache --taint-analysis
ERROR: TaintedSql - html/db.php:21:26 - Detected tainted SQL (see https://psalm.dev/244)
$_GET
<no known location>
$_GET['guest_id'] - html/hidden-panel.php:6:65
$sql = "SELECT id, firstname, lastname FROM MyGuests WHERE id=".$_GET['guest_id'];
concat - html/hidden-panel.php:6:8
$sql = "SELECT id, firstname, lastname FROM MyGuests WHERE id=".$_GET['guest_id'];
$sql - html/hidden-panel.php:6:1
$sql = "SELECT id, firstname, lastname FROM MyGuests WHERE id=".$_GET['guest_id'];
call to db_query - html/hidden-panel.php:7:27
$result = db_query($conn, $sql);
ERROR: TaintedSql - html/db.php:21:26 - Detected tainted SQL (see https://psalm.dev/244)
$_GET
<no known location>
$_GET['log_id'] - html/hidden-panel.php:19:87
$sql2 = "SELECT id, logtext FROM logs WHERE id='".preg_replace('/[^a-z0-9A-Z"]/', "", $_GET['log_id']). "'";
call to preg_replace - html/hidden-panel.php:19:87
$sql2 = "SELECT id, logtext FROM logs WHERE id='".preg_replace('/[^a-z0-9A-Z"]/', "", $_GET['log_id']). "'";
preg_replace#3 - html/hidden-panel.php:19:87
$sql2 = "SELECT id, logtext FROM logs WHERE id='".preg_replace('/[^a-z0-9A-Z"]/', "", $_GET['log_id']). "'";
preg_replace - vendor/vimeo/psalm/stubs/CoreGenericFunctions.phpstub:1182:10
function preg_replace($pattern, $replacement, $subject, int $limit = -1, &$count = null) {}
concat - html/hidden-panel.php:19:9
$sql2 = "SELECT id, logtext FROM logs WHERE id='".preg_replace('/[^a-z0-9A-Z"]/', "", $_GET['log_id']). "'";
concat - html/hidden-panel.php:19:9
$sql2 = "SELECT id, logtext FROM logs WHERE id='".preg_replace('/[^a-z0-9A-Z"]/', "", $_GET['log_id']). "'";
$sql2 - html/hidden-panel.php:19:1
$sql2 = "SELECT id, logtext FROM logs WHERE id='".preg_replace('/[^a-z0-9A-Z"]/', "", $_GET['log_id']). "'";
call to db_query - html/hidden-panel.php:20:28
$result2 = db_query($conn, $sql2);Note: You will get a third error repeating one of the previous ones. This is because mysqli_query is still considered a valid sink (Psalm's has a built-in list of default sinks), so you should still have the original alert on top of the new ones.
Finally, if you compare Psalm's results with our manual review, you should notice that there are some differences in the results:
Manual ReviewPsalm ReviewVerdict$sqlVulnerableVulnerableOK$sql2Not VulnerableVulnerableFalse Positive$sql3VulnerableNot VulnerableFalse Negative
A certain level of false positives and false negatives is always expected when using SAST tools. As with any other tool, you must manually check the report to search for any errors. SAST is an excellent complement to manual reviews, but should never be considered as their replacement.
Answer the questions below
What type of error occurs when the tool reports on a vulnerability that isn't present in the code?
Hint: The tool reports on a vulnerability that isn't present in the code.
How many errors are reported after annotating the code as instructed in this task and re-running Psalm?
Hint: Count the errors.
Task 6 SAST in the Development Cycle
SAST is one of the first tools to appear during the development lifecycle. It is often implemented during the coding stage, as there's no need to have a functional application to use it.

Depending on each case, SAST can be implemented in one of the following ways:
- CI/CD integration: Each time a pull request or a merge is made, SAST tools will check the code for vulnerabilities. Checking pull requests ensures that the code that makes it to merges has undergone at least a basic security check. On some occasions, instead of checking every single pull request, executing SAST scans only at merges may help prevent slowdowns in the development pipeline, as it avoids making all developers wait for full SAST scans.
- IDE integration: SAST tools can be integrated into the developers' favourite IDEs instead of waiting for a pull request or merge to occur. This way, the code can be fixed as early as possible, saving time further ahead in the project.
Note that you may want SAST running on both the developers' IDEs and your CI/CD pipeline, which would be valid. For example, IDE tools may run basic structural checks and enforce secure coding guidelines, while CI/CD integrations may run more time-consuming dataflow/taint analysis. Remember that your specific setup will depend on the requirements of each project and should be evaluated by the team carefully.
If you want to learn how security tools can be integrated into a CI/CD pipeline, check the DAST room for an example of integrating a DAST tool into a Jenkins pipeline. The process with SAST tools is pretty similar, so we won't repeat it here.
Integrating SAST in IDEs
Your virtual machine has the VS Code editor installed and already configured to use a couple of SAST tools:
- Psalm: The tool we've been using supports IDE integration by installing the Psalm plugin into VS Code directly from the Visual Studio Marketplace(opens in new tab). This plugin will check anything you type in real-time and show you the same alerts as the console version directly into your code. Taint analysis won't be available, so you'll only see the structural problems reported on a basic Psalm analysis.
- Semgrep: Yet another SAST tool that can be installed into VS Code directly from the Visual Studio Marketplace(opens in new tab). Just as with Psalm, it will show inline alerts directly in your code. Semgrep even allows us to build custom rules if needed. You can check the rules that are loaded for this project on the
semgrep-rulesdirectory inside the project's directory. The specifics on how to build Semgrep rules will be left for a future room, so don't worry about them now. You can check the rules in the directory, but this won't be required for this room.
Both tools will work similarly by showing any problems detected directly inline in your code. The only notable difference is that Semgrep will run when you start VS Code and will show you the problems it detects on all of the files, while Psalm will only show you issues related to the file you are currently editing. The plugins will add the following information to your IDE screen:

For each line where issues are detected, you can get additional information by hovering the mouse pointer over it. Here's what you would get by hovering over line 46 of login.php:

You can also check the complete list of issues by clicking the Errors indicator at the bottom of VS Code's screen:

Having your IDE check for problems allows you to produce cleaner code as a developer, contributing significantly to the overall security of your final application.
Using both tools in your IDE, answer the questions at the end of the task.
Answer the questions below
For this task's questions, we will analyse an old version of ReciPHP, a small open-source app. Before continuing, make sure to open the reciphp.code-workspace icon on your desktop. This will open a VS Code workspace where the project is already loaded for you. VS Code will take around 3 minutes to load, so be patient.
How many problems in total are detected by Semgrep in this project?
Hint:

How many problems are detected in the showrecipe.inc.php file?
Hint: Tells you on the right across the file
Open showrecipe.inc.php. There are two types of problems being reported by Semgrep in this file. One is identified as "tainted-sql-string" and refers to possible SQL injections.
What other problem identifier is reported by Semgrep in this file? (Write the id reported by Semgrep)
Hint: it's not the tainted-sql-string
What type of vulnerability is associated with the problem identifier on the previous question?
Hint: Hover your mouse over the error and it will tell you what vulnerability is associated.
Task 7: Conclusion
SAST is one of the many techniques we can use to improve the security of our applications while they are still being developed. We have shown how to use Psalm, one of the many available SAST tools and how much time it saves us compared to manual reviews. As with any other automated tool, it is essential to validate the results manually, as false positives may be reported.
Be sure to check the DAST room to learn how Dynamic Analysis complements SAST to strengthen your secure development process.