Introducing SASTGPT: an AI-powered SAST

SASTGPT is an AI-powered assistive tool that leverages the capabilities of existing Large Language Models to find security vulnerabilities in code. No hype, no long pitch, let’s dive into some scan examples performed using SASTGPT and the approach it takes. Example 1 The following is a simple nodejs(express) app that is vulnerable to XSS. const express = require('express'); const app = express(); app.use(express.urlencoded({ extended: true })); app.get('/', (req, res) => { const userInput = req.query.input || ''; const response = ` Vulnerable XSS Demo Submit You entered: ${userInput} `; res.send(response); }); app.listen(3000, () => console.log('Server running on http://localhost:3000')); The vulnerability is straightforward and easily detectable by having a quick glance at the code. The unsanitized input query parameter is directly interpolated into a string, which is then returned in the response. Let’s see what SASTGPT outputs. For this simple example, what we see is quite good results. SASTGPT is outputting what more or less we explained in words. It also includes the arrows you see in the screenshot to further visualize how the bad input is flowing into code. Breaking down what we see in the screenshot is: 7: The application gets user input from the URL query string using req.query.input. 14: The input userInput is directly interpolated into the HTML response without any sanitization. 16: The response containing potentially malicious userInput is sent back to the user’s browser. Below the actual vulnerable code, SASTGPT provides the Suggested Fix and the Steps to reproduce. Let’s have a look at the Steps to reproduce and try to fully exploit the vulnerability. On step 2 we have the crafted request containing the payload. Opening it in the browser we can see the exploit actually works. Example 2 A Go application vulnerable in SSRF. package main import ( "fmt" "io/ioutil" "net/http" "net/url" "strings" ) func fetchURL(target string) (string, error) { resp, err := http.Get(target) if err != nil { return "", err } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { return "", err } return string(body), nil } func isAllowedURL(target string) bool { parsedURL, err := url.Parse(target) if err != nil { return false } host := strings.ToLower(parsedURL.Host) if strings.Contains(host, "localhost") || host == "127.0.0.1" { return false } return true } func handler(w http.ResponseWriter, r *http.Request) { targetURL := r.URL.Query().Get("url") if targetURL == "" { http.Error(w, "Missing url parameter", http.StatusBadRequest) return } if !isAllowedURL(targetURL) { http.Error(w, "URL not allowed", http.StatusForbidden) return } content, err := fetchURL(targetURL) if err != nil { http.Error(w, "Failed to fetch URL", http.StatusInternalServerError) return } fmt.Fprintf(w, "Fetched content: %s", content) } func main() { http.HandleFunc("/proxy", handler) http.ListenAndServe(":8080", nil) } This Go script simulates a very minimal/simple proxy. The handler requires a URL query param which is passed to the isAllowedUrl function, checking if the URL is not pointing to localhost or 127.0.0.1. Then the URL is passed to the fetchURL which makes a GET request to the target URL. In this simple example we can see that this is vulnerable to SSRF because the isAllowedUrl is easily bypassable by: Adding a port to the URL http://localhost:80 Fetching instance metadata using http://169.254.169.254/latest/meta-data/ Use hexadecimal(or decimal) http://0x7f000001 and many more alternatives. Let’s see what SASTGPT outputs for this vulnerable example. Like in the previous example, SASTGPT follows the bad input and provides us insights on each line to make us understand the vulnerability better. It has also analyzed the isAllowedURL sanitizer and indicates that the check we did on that function can be bypassed. Let’s jump down to reproduction steps and see what SASTGPT has generated. It looks like the Step 2 is correct and yet another way to bypass the sanitizer that we did not mention. The payload in Step 2, http://[::1] is a URL that points to the IPv6 loopback address (::1), which is equivalent to 127.0.0.1 in IPv4. This means it refers to the local machine (localhost). However, the Step 3 description is correct but the actual payload is constructed incorrectly. The description states that a decimal IP should be used (127.0.0.1 is 2130706433) but the payload is written as http://127.0.0.1:8080. While this still works because the port 8080 is included, we can see how the LLM may provide wrong or partially right information. I have started a simple python server o

Apr 14, 2025 - 15:29
 0
Introducing SASTGPT: an AI-powered SAST

SASTGPT is an AI-powered assistive tool that leverages the capabilities of existing Large Language Models to find security vulnerabilities in code. No hype, no long pitch, let’s dive into some scan examples performed using SASTGPT and the approach it takes.

Example 1

The following is a simple nodejs(express) app that is vulnerable to XSS.

const express = require('express');
const app = express();

app.use(express.urlencoded({ extended: true }));

app.get('/', (req, res) => {
   const userInput = req.query.input || '';

   const response = `
       

Vulnerable XSS Demo

You entered: ${userInput} `; res.send(response); }); app.listen(3000, () => console.log('Server running on http://localhost:3000'));

The vulnerability is straightforward and easily detectable by having a quick glance at the code. The unsanitized input query parameter is directly interpolated into a string, which is then returned in the response. Let’s see what SASTGPT outputs.

Image description

For this simple example, what we see is quite good results. SASTGPT is outputting what more or less we explained in words. It also includes the arrows you see in the screenshot to further visualize how the bad input is flowing into code. Breaking down what we see in the screenshot is:

  • 7: The application gets user input from the URL query string using req.query.input.
  • 14: The input userInput is directly interpolated into the HTML response without any sanitization.
  • 16: The response containing potentially malicious userInput is sent back to the user’s browser.

Below the actual vulnerable code, SASTGPT provides the Suggested Fix and the Steps to reproduce. Let’s have a look at the Steps to reproduce and try to fully exploit the vulnerability.

Image description

On step 2 we have the crafted request containing the payload. Opening it in the browser we can see the exploit actually works.

Image description

Example 2

A Go application vulnerable in SSRF.

package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
    "net/url"
    "strings"
)

func fetchURL(target string) (string, error) {
    resp, err := http.Get(target)
    if err != nil {
        return "", err
    }
    defer resp.Body.Close()

    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        return "", err
    }
    return string(body), nil
}

func isAllowedURL(target string) bool {
    parsedURL, err := url.Parse(target)
    if err != nil {
        return false
    }

    host := strings.ToLower(parsedURL.Host)

    if strings.Contains(host, "localhost") || host == "127.0.0.1" {
        return false
    }

    return true
}

func handler(w http.ResponseWriter, r *http.Request) {
    targetURL := r.URL.Query().Get("url")
    if targetURL == "" {
        http.Error(w, "Missing url parameter", http.StatusBadRequest)
        return
    }

    if !isAllowedURL(targetURL) {
        http.Error(w, "URL not allowed", http.StatusForbidden)
        return
    }

    content, err := fetchURL(targetURL)
    if err != nil {
        http.Error(w, "Failed to fetch URL", http.StatusInternalServerError)
        return
    }

    fmt.Fprintf(w, "Fetched content: %s", content)
}

func main() {
    http.HandleFunc("/proxy", handler)
    http.ListenAndServe(":8080", nil)
} 

This Go script simulates a very minimal/simple proxy. The handler requires a URL query param which is passed to the isAllowedUrl function, checking if the URL is not pointing to localhost or 127.0.0.1. Then the URL is passed to the fetchURL which makes a GET request to the target URL. In this simple example we can see that this is vulnerable to SSRF because the isAllowedUrl is easily bypassable by:

  • Adding a port to the URL http://localhost:80
  • Fetching instance metadata using http://169.254.169.254/latest/meta-data/
  • Use hexadecimal(or decimal) http://0x7f000001
  • and many more alternatives.

Let’s see what SASTGPT outputs for this vulnerable example.

Image description

Like in the previous example, SASTGPT follows the bad input and provides us insights on each line to make us understand the vulnerability better. It has also analyzed the isAllowedURL sanitizer and indicates that the check we did on that function can be bypassed. Let’s jump down to reproduction steps and see what SASTGPT has generated.

Image description

It looks like the Step 2 is correct and yet another way to bypass the sanitizer that we did not mention. The payload in Step 2, http://[::1] is a URL that points to the IPv6 loopback address (::1), which is equivalent to 127.0.0.1 in IPv4. This means it refers to the local machine (localhost). However, the Step 3 description is correct but the actual payload is constructed incorrectly. The description states that a decimal IP should be used (127.0.0.1 is 2130706433) but the payload is written as http://127.0.0.1:8080. While this still works because the port 8080 is included, we can see how the LLM may provide wrong or partially right information.

I have started a simple python server on port 80 and will try to access it from Go running on 8000. Let's execute the Step 2 command and see the result.

Image description

Summary

LLMs can perform Static Application Security Testing. There are limitations, but even with the limitations in place we still get impressive results. The examples above are simple and straightforward, but in the upcoming days, I will try to improve the tool, write a more detailed blog on how SASTGPT works and provide more complex examples—if time permits.

Access SASTGPT

SASTGPT is up and running on https://sastgpt.com. Since this is an MVP, it is running on minimal resources so you can register and perform a limited amount of scans for free. If you are interested in performing more scans or using the Project Upload feature, please contact me on info@mail.sastgpt.com.