Static Application Security Testing
By Nicolas Béguier (Offensive & Defensive Security Engineer)
Static Application Security Testing (SAST) is a set of technologies designed to analyze application and design conditions that indicate security vulnerabilities. SAST solutions analyze an application in a state of non-execution.
Working in a white box environment provides a better understanding of the application and the interaction between all of its components. In contrast, black box testing of a running application is also called Dynamic Application Security Testing (DAST) and will not be detailed in this article.
Why we need a SAST
Checking each commit and blocking them in case of vulnerability sounds perfect, avoiding false positive is a bit tricky though.
If the threshold is too low, we let everything pass and in the end there is a false sense of security.
At the opposite, setting the threshold too high is blocking everyone, so they have to find a way to bypass the check in the case of a false positive: In the long run, they no longer ask themselves why and they bypass the check.
The best solution is to block checks that you are sure of, and alert in case of any doubt.
Easy to say, right?
If we focus on alerting, the granularity of the commit is no longer necessary, that’s why we didn’t use any CI/CD pipelines. A human will go through alerts from time to time and check if it is a false positive or not.
The time for a commit to reach production is not immediate, this time can be very very short but generally there are some manual tests before, to make sure that the user experience is still OK.
The approach of an analysis with a high threshold once a day was our first iteration, then we moved on to an analysis by hour. This time can of course be reduced and put the whole thing into the CI/CD.
When looking for SAST solutions, you first come across tools that check dependencies. It’s good, but it’s not enough. What matters in our case is the code written by our developers, not that of others.
Then there are tools that check the quality of the code with one or two security modules, which ultimately check if there is a password in the code.
The magic tool that works with all languages is either expensive or we miss it.
Fortunately, there are open-source tools that work very well, but are dedicated to a language.
At leboncoin, we have chosen the following tools:
- Golang: GoSec
- Android (Kotlin / Java) & iOS (Objective-C / Swift): Mobile-Security-Framework — MobSF
- NodeJS (RocJS / NextJS): njsscan
For the story, Ajin Abraham, a famous security researcher, is the author of MobSF and njsscan. The community behind MobSF is huge, which is why it has a lot of features, but njsscan is full of great ideas.
About gosec, this is a collaborative project supported by a massive community and several companies.
What does it do ?
gosec is a security must in Golang. Updated very regularly, it is dedicated to the search for vulnerability in the code.
Beyond the search for credentials in the code, the rules in G2XX are very relevant.
SQL query analysis can distinguish one prepared query from another with user inputs directly in the query.
Also, the non-escaped html code in the templates and shell commands is a plus.
MobSF, very famous in the mobile pentest, gives a solid analysis of the Android (Java, Kotlin) and iOS (Objective-C, Swift) source code.
For Android, there is an analysis of the AndroidManifest.xml to find a configuration vulnerability (backup, intention-filter, debug mode, etc.), as well as a code analysis to look for data stored in an insecure manner (shared preferences, sdcard), WebView and of course, secrets :)
For iOS, there is code analysis similar to Android. The manifest is compensated by the plist analysis, looking for exceptions in the Transport Security App (ATS).
The set of rules is smart. Alerts can be string comparisons using
==, these operators are vulnerable to timing attacks in NodeJS. But also spot error messages with stack traces that can expose sensitive information, a user credit card in the event of a crash during payment for example.
We are currently scanning:
- 1 Golang monorepo, including a hundred of micro-services
- 1 Android monorepo, with a shared codebase (approximately 130)
- 23 iOS repository, micro-components archi
- 4 NodeJS repositories (RocJS and NextJS)
Which gives about 159 scans per iteration
Our SAST platform acts in 3 stages:
Updating the repositories to scan: broadly speaking, this is a git pull
Launching the scans and creating a report: At leboncoin, each repository has its own architecture, the idea is to have a gosec and mobsf module that scans a repository regardless of the format.
Around, you must create a wrapper to manage the flavor of your custom repository.
Gosec example of a vulnerable SQL query, especially if the entries are under user control:
"details": "SQL string formatting",
"code": "fmt.Sprintf("INSERT INTO some_table (%s) VALUES (%s)", columnNamesStr, placeholders)",
Example of MobSF on Android, where an Activity has an intent-filter, therefore accessible from all other mobile applications:
“title”: “Activity (com.example.CustomActivity) is not Protected. An intent-filter exists.”,
“desc”: “An Activity is found to be shared with other apps on the device therefore leaving it accessible to any other application on the device. The presence of intent-filter indicates that the Activity is explicitly exported.”,
“name”: “is not Protected.An intent-filter exists.”,
Transformation of the report into Slack alerts: The alerting module compares the last report with the previous one and for each vulnerability, medium or high in our case, it sends a Slack alert.
If you don’t have a continuous pentest, there will always be a time when features come out and no one has a security check.
What’s next ?
We are currently testing new feature detection modules. This is a very business point of view, as it adheres to the way a feature is implemented, but it gives a good starting point for a pentest.
In addition, better detection of secrets is under development, using shhgit rules.
For the scheduler, we will quickly leave the traditional cron for our Patrowl infrastructure, it is our tool for orchestrating security operations: https://patrowl.io/home
The main goal would be to create a Patrowl Engine, which takes as input the repository name to be scanned.
The Patrowl Manager will regularly call the Engine, collect vulnerabilities and use our usual alert policy.