🔒 AISAST Security Report

Project: /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m
Generated: 2025-12-03 00:02:22
Files Scanned
22
Lines of Code
859
True Positives
19
False Positives
9
Critical
3
High
16
Medium
8
Low
1

📚 Findings by CWE

CWE-20 (1 findings)

  • Potential data flow sink — /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/src/main/java/com/scalesec/vulnado/Cowsay.java:17

CWE-209 (6 findings)

  • Information Exposure Through Error Messages — /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/src/main/java/com/scalesec/vulnado/Comment.java:55
  • Information Exposure Through Error Messages — /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/src/main/java/com/scalesec/vulnado/Postgres.java:100
  • Information Exposure Through Error Messages — /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/src/main/java/com/scalesec/vulnado/Postgres.java:114
  • Information Exposure Through Error Messages — /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/src/main/java/com/scalesec/vulnado/User.java:34
  • Information Exposure Through Error Messages — /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/src/main/java/com/scalesec/vulnado/User.java:58
  • Information Exposure Through Error Messages — /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/src/main/java/com/scalesec/vulnado/Cowsay.java:24

CWE-327 (1 findings)

  • Weak Cryptographic Hash (MD5) — /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/src/main/java/com/scalesec/vulnado/Postgres.java:67

CWE-502 (2 findings)

  • Insecure Deserialization — /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/src/main/java/com/scalesec/vulnado/CommentsController.java:25
  • Insecure Deserialization — /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/src/main/java/com/scalesec/vulnado/LoginController.java:29

CWE-78 (1 findings)

  • Command Injection — /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/src/main/java/com/scalesec/vulnado/Cowsay.java:11

CWE-79 (5 findings)

  • Cross-Site Scripting (XSS) — /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/client/index.html:73
  • XSS - jQuery .html() — /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/client/js/index.js:2
  • XSS - jQuery .html() — /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/client/js/index.js:28
  • XSS - Template expression in HTML context — /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/src/main/java/com/scalesec/vulnado/CommentsController.java:13
  • XSS - Template expression in HTML context — /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/src/main/java/com/scalesec/vulnado/LoginController.java:14

CWE-798 (4 findings)

  • Hardcoded Secret in Configuration — /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/src/main/resources/application.properties:1
  • Hardcoded Credentials in Configuration — /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/docker-compose.yml:10
  • Hardcoded Credentials in Configuration — /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/docker-compose.yml:25
  • Hardcoded Database Password — /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/docker-compose.yml:26

CWE-862 (1 findings)

  • Missing Authorization Check — /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/src/main/java/com/scalesec/vulnado/CommentsController.java:31

CWE-89 (5 findings)

  • SQL Injection — /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/src/main/java/com/scalesec/vulnado/User.java:47
  • SQL Injection - Java executeQuery with variable — /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/src/main/java/com/scalesec/vulnado/Comment.java:44
  • SQL Injection - SQL string concatenation — /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/src/main/java/com/scalesec/vulnado/Comment.java:43
  • SQL Injection risk - Java Statement (use PreparedStatement) — /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/src/main/java/com/scalesec/vulnado/Postgres.java:35
  • SQL Injection - SQL string concatenation — /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/src/main/java/com/scalesec/vulnado/Postgres.java:42

CWE-918 (2 findings)

  • Server-Side Request Forgery (SSRF) — /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/src/main/java/com/scalesec/vulnado/LinkLister.java:16
  • Server-Side Request Forgery (SSRF) - Incomplete Protection — /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/src/main/java/com/scalesec/vulnado/LinkLister.java:32
CRITICAL CWE-89 ✓ AI VERIFIED TRUE POSITIVE

SQL Injection

📍 User.java : Line 47
Full Path: /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/src/main/java/com/scalesec/vulnado/User.java

⚠️ Vulnerable Code

ResultSet rs = stmt.executeQuery(query);

💡 Explanation

User input from the login request flows through the LoginController to User.fetch() where it is directly concatenated into a SQL query without sanitization. An attacker can inject malicious SQL through the username parameter during login, potentially bypassing authentication or extracting sensitive data from the database.

🔄 Data Flow Analysis

  1. Step 1 [SOURCE]: User input received from HTTP request body containing username [LoginController.java:19] → `LoginResponse login(@RequestBody LoginRequest input)`
  2. Step 2 [FLOW]: Username from user input passed to User.fetch() method [LoginController.java:20] → `User user = User.fetch(input.username);`
  3. Step 3 [SINK]: User-controlled username concatenated directly into SQL query [User.java:47] → `String query = "select * from users where username = '" + un + "' limit 1";`
  4. Step 4 [SINK]: Vulnerable SQL query executed against database [User.java:49] → `ResultSet rs = stmt.executeQuery(query);`

✅ Recommended Fix

String query = "select * from users where username = ? limit 1";
PreparedStatement pstmt = cxn.prepareStatement(query);
pstmt.setString(1, un);
ResultSet rs = pstmt.executeQuery();

Fix applied to prevent SQL Injection

CRITICAL CWE-918 ✓ AI VERIFIED TRUE POSITIVE

Server-Side Request Forgery (SSRF)

📍 LinkLister.java : Line 16
Full Path: /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/src/main/java/com/scalesec/vulnado/LinkLister.java

⚠️ Vulnerable Code

Document doc = Jsoup.connect(url).get();

💡 Explanation

User-controlled URL parameter from the request is passed directly to Jsoup.connect() without adequate validation. An attacker can make the server send HTTP requests to arbitrary internal or external URLs, potentially accessing internal services, cloud metadata endpoints (169.254.169.254), or performing port scanning. The /links endpoint has no protections against this attack.

🔄 Data Flow Analysis

  1. Step 1 [SOURCE]: User-controlled URL parameter received from HTTP request [LinksController.java:16] → `List<String> links(@RequestParam String url) throws IOException{`
  2. Step 2 [FLOW]: URL passed to LinkLister.getLinks method [LinksController.java:17] → `return LinkLister.getLinks(url);`
  3. Step 3 [SINK]: User-controlled URL used to make HTTP request via Jsoup, enabling SSRF attacks [LinkLister.java:16] → `Document doc = Jsoup.connect(url).get();`

✅ Recommended Fix

URL aUrl = new URL(url); String host = aUrl.getHost(); if (!isAllowedHost(host) || isPrivateIP(host) || host.equals("169.254.169.254")) { throw new BadRequest("Invalid URL"); }

Fix applied to prevent Server-Side Request Forgery (SSRF)

CRITICAL CWE-78 ✓ AI VERIFIED TRUE POSITIVE

Command Injection

📍 Cowsay.java : Line 11
Full Path: /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/src/main/java/com/scalesec/vulnado/Cowsay.java

⚠️ Vulnerable Code

processBuilder.command("bash", "-c", cmd);

💡 Explanation

User input from the 'input' request parameter flows through CowController.cowsay() to Cowsay.run() where it is concatenated directly into a shell command string. The command is then executed via ProcessBuilder with 'bash -c', allowing an attacker to inject arbitrary shell commands by breaking out of the single quotes (e.g., using payload like: ' ; rm -rf / ; ').

🔄 Data Flow Analysis

  1. Step 1 [SOURCE]: User-controlled input from HTTP request parameter 'input' [CowController.java:12] → `String cowsay(@RequestParam(defaultValue = "I love Linux!") String input)`
  2. Step 2 [FLOW]: User input passed to Cowsay.run() method [CowController.java:13] → `return Cowsay.run(input);`
  3. Step 3 [SINK]: User input concatenated into shell command string [Cowsay.java:9] → `String cmd = "/usr/games/cowsay '" + input + "'";`
  4. Step 4 [SINK]: Command string containing user input executed via bash shell [Cowsay.java:11] → `processBuilder.command("bash", "-c", cmd);`

✅ Recommended Fix

String sanitized = input.replaceAll("[^a-zA-Z0-9 ]", ""); processBuilder.command("/usr/games/cowsay", sanitized);

Fix applied to prevent Command Injection

HIGH CWE-89 ✓ AI VERIFIED FALSE POSITIVE

SQL Injection - Java executeQuery with variable

📍 Comment.java : Line 44
Full Path: /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/src/main/java/com/scalesec/vulnado/Comment.java

⚠️ Vulnerable Code

  37 |     Statement stmt = null;
  38 |     List<Comment> comments = new ArrayList();
  39 |     try {
  40 |       Connection cxn = Postgres.connection();
  41 |       stmt = cxn.createStatement();
  42 | 
  43 |       String query = "select * from comments;";
  44 |       ResultSet rs = stmt.executeQuery(query);
  45 |       while (rs.next()) {
  46 |         String id = rs.getString("id");
  47 |         String username = rs.getString("username");
  48 |         String body = rs.getString("body");
  49 |         Timestamp created_on = rs.getTimestamp("created_on");
  50 |         Comment c = new Comment(id, username, body, created_on);
  51 |         comments.add(c);

💡 Explanation

FALSE POSITIVE: Line 44 executes a query, but line 43 shows the query is a hardcoded string literal 'select * from comments;' with no user input concatenation or variables involved.

HIGH CWE-89 ✓ AI VERIFIED FALSE POSITIVE

SQL Injection - SQL string concatenation

📍 Comment.java : Line 43
Full Path: /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/src/main/java/com/scalesec/vulnado/Comment.java

⚠️ Vulnerable Code

  36 |   public static List<Comment> fetch_all() {
  37 |     Statement stmt = null;
  38 |     List<Comment> comments = new ArrayList();
  39 |     try {
  40 |       Connection cxn = Postgres.connection();
  41 |       stmt = cxn.createStatement();
  42 | 
  43 |       String query = "select * from comments;";
  44 |       ResultSet rs = stmt.executeQuery(query);
  45 |       while (rs.next()) {
  46 |         String id = rs.getString("id");
  47 |         String username = rs.getString("username");
  48 |         String body = rs.getString("body");
  49 |         Timestamp created_on = rs.getTimestamp("created_on");
  50 |         Comment c = new Comment(id, username, body, created_on);

💡 Explanation

FALSE POSITIVE: Line 43 contains a hardcoded SQL string literal 'select * from comments;' with no concatenation of user input. This is a static query, not SQL injection.

HIGH CWE-89 ✓ AI VERIFIED FALSE POSITIVE

SQL Injection risk - Java Statement (use PreparedStatement)

📍 Postgres.java : Line 35
Full Path: /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/src/main/java/com/scalesec/vulnado/Postgres.java

⚠️ Vulnerable Code

  28 |         }
  29 |         return null;
  30 |     }
  31 |     public static void setup(){
  32 |         try {
  33 |             System.out.println("Setting up Database...");
  34 |             Connection c = connection();
  35 |             Statement stmt = c.createStatement();
  36 | 
  37 |             // Create Schema
  38 |             stmt.executeUpdate("CREATE TABLE IF NOT EXISTS users(user_id VARCHAR (36) PRIMARY KEY, username VARCHAR (50) UNIQUE NOT NULL, password VARCHAR (50) NOT NULL, created_on TIMESTAMP NOT NULL, last_login TIMESTAMP)");
  39 |             stmt.executeUpdate("CREATE TABLE IF NOT EXISTS comments(id VARCHAR (36) PRIMARY KEY, username VARCHAR (36), body VARCHAR (500), created_on TIMESTAMP NOT NULL)");
  40 | 
  41 |             // Clean up any existing data
  42 |             stmt.executeUpdate("DELETE FROM users");

💡 Explanation

FALSE POSITIVE: Line 35 creates a Statement object, but this alone is not a vulnerability. The Statement is used with hardcoded SQL queries (lines 38-39, 42-43) with no user input. Later methods properly use PreparedStatement for user data.

HIGH CWE-89 ✓ AI VERIFIED FALSE POSITIVE

SQL Injection - SQL string concatenation

📍 Postgres.java : Line 42
Full Path: /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/src/main/java/com/scalesec/vulnado/Postgres.java

⚠️ Vulnerable Code

  35 |             Statement stmt = c.createStatement();
  36 | 
  37 |             // Create Schema
  38 |             stmt.executeUpdate("CREATE TABLE IF NOT EXISTS users(user_id VARCHAR (36) PRIMARY KEY, username VARCHAR (50) UNIQUE NOT NULL, password VARCHAR (50) NOT NULL, created_on TIMESTAMP NOT NULL, last_login TIMESTAMP)");
  39 |             stmt.executeUpdate("CREATE TABLE IF NOT EXISTS comments(id VARCHAR (36) PRIMARY KEY, username VARCHAR (36), body VARCHAR (500), created_on TIMESTAMP NOT NULL)");
  40 | 
  41 |             // Clean up any existing data
  42 |             stmt.executeUpdate("DELETE FROM users");
  43 |             stmt.executeUpdate("DELETE FROM comments");
  44 | 
  45 |             // Insert seed data
  46 |             insertUser("admin", "!!SuperSecretAdmin!!");
  47 |             insertUser("alice", "AlicePassword!");
  48 |             insertUser("bob", "BobPassword!");
  49 |             insertUser("eve", "$EVELknev^l");

💡 Explanation

FALSE POSITIVE: Line 42 executes 'DELETE FROM users' which is a hardcoded SQL string with no user input concatenation. This is part of database setup/initialization code (in setup() method) that cleans existing data.

HIGH CWE-502 ✓ AI VERIFIED TRUE POSITIVE

Insecure Deserialization

📍 CommentsController.java : Line 25
Full Path: /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/src/main/java/com/scalesec/vulnado/CommentsController.java

⚠️ Vulnerable Code

class CommentRequest implements Serializable

💡 Explanation

The CommentRequest class implements Serializable and is used with @RequestBody annotation. Spring Boot can deserialize arbitrary JSON to Java objects. While Spring's default JSON deserialization is relatively safe, implementing Serializable unnecessarily increases attack surface and could be exploited if custom deserialization logic is added or if alternative deserializers are configured.

🔄 Data Flow Analysis

  1. Step 1 [SOURCE]: User-controlled JSON data received and deserialized into CommentRequest object [CommentsController.java:25] → `Comment createComment(@RequestHeader(value="x-auth-token") String token, @Reques`
  2. Step 2 [SINK]: Class implements Serializable interface, enabling potential deserialization attacks [CommentsController.java:36] → `class CommentRequest implements Serializable`

✅ Recommended Fix

class CommentRequest {
  public String username;
  public String body;
}

Fix applied to prevent Insecure Deserialization

HIGH CWE-502 ✓ AI VERIFIED TRUE POSITIVE

Insecure Deserialization

📍 LoginController.java : Line 29
Full Path: /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/src/main/java/com/scalesec/vulnado/LoginController.java

⚠️ Vulnerable Code

class LoginRequest implements Serializable

💡 Explanation

The LoginRequest class implements Serializable and is used with @RequestBody annotation for JSON deserialization. This unnecessarily marks the class as serializable when only JSON binding is needed. This could enable deserialization attacks if the application configuration changes or custom deserializers are introduced.

🔄 Data Flow Analysis

  1. Step 1 [SOURCE]: User-controlled JSON data received and deserialized into LoginRequest object [LoginController.java:19] → `LoginResponse login(@RequestBody LoginRequest input)`
  2. Step 2 [SINK]: Class implements Serializable interface, enabling potential deserialization attacks [LoginController.java:29] → `class LoginRequest implements Serializable`

✅ Recommended Fix

class LoginRequest {
  public String username;
  public String password;
}

Fix applied to prevent Insecure Deserialization

HIGH CWE-327 ✓ AI VERIFIED TRUE POSITIVE

Weak Cryptographic Hash (MD5)

📍 Postgres.java : Line 67
Full Path: /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/src/main/java/com/scalesec/vulnado/Postgres.java

⚠️ Vulnerable Code

MessageDigest md = MessageDigest.getInstance("MD5");

💡 Explanation

The application uses MD5 for password hashing, which is cryptographically broken and unsuitable for password storage. MD5 is vulnerable to collision attacks and can be rapidly brute-forced with modern hardware. Passwords hashed with MD5 can be easily cracked, compromising user accounts.

🔄 Data Flow Analysis

  1. Step 1 [SOURCE]: User password received from login request [LoginController.java:19] → `LoginResponse login(@RequestBody LoginRequest input)`
  2. Step 2 [FLOW]: Password hashed using MD5 for comparison [LoginController.java:21] → `if (Postgres.md5(input.password).equals(user.hashedPassword))`
  3. Step 3 [SINK]: MD5 algorithm used for password hashing [Postgres.java:67] → `MessageDigest md = MessageDigest.getInstance("MD5");`

✅ Recommended Fix

import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
String hashedPassword = encoder.encode(password);
boolean matches = encoder.matches(inputPassword, storedHash);

Fix applied to prevent Weak Cryptographic Hash (MD5)

HIGH CWE-862 ✓ AI VERIFIED TRUE POSITIVE

Missing Authorization Check

📍 CommentsController.java : Line 31
Full Path: /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/src/main/java/com/scalesec/vulnado/CommentsController.java

⚠️ Vulnerable Code

String sql = "DELETE FROM comments where id = ?";

💡 Explanation

The deleteComment endpoint accepts a comment ID from the user but does not verify that the authenticated user owns that comment or has permission to delete it. Any authenticated user can delete any comment by supplying different ID values, leading to unauthorized data modification.

🔄 Data Flow Analysis

  1. Step 1 [SOURCE]: User provides comment ID via path parameter [CommentsController.java:31] → `Boolean deleteComment(@RequestHeader(value="x-auth-token") String token, @PathVa`
  2. Step 2 [FLOW]: ID passed directly to delete method without authorization check [CommentsController.java:32] → `return Comment.delete(id);`
  3. Step 3 [SINK]: Comment deleted without verifying user ownership [Comment.java:64] → `String sql = "DELETE FROM comments where id = ?";`

✅ Recommended Fix

String username = User.getUsernameFromToken(token);
Comment comment = Comment.findById(id);
if (comment == null || !comment.username.equals(username)) {
  throw new Unauthorized("Cannot delete this comment");
}
return Comment.delete(id);

Fix applied to prevent Missing Authorization Check

HIGH CWE-918 ✓ AI VERIFIED TRUE POSITIVE

Server-Side Request Forgery (SSRF) - Incomplete Protection

📍 LinkLister.java : Line 32
Full Path: /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/src/main/java/com/scalesec/vulnado/LinkLister.java

⚠️ Vulnerable Code

return getLinks(url);

💡 Explanation

The getLinksV2 method attempts to prevent SSRF by blocking private IP ranges, but the validation is incomplete and bypassable. It doesn't block localhost (127.0.0.1), link-local addresses (169.254.x.x for cloud metadata), IPv6 addresses, DNS rebinding attacks, or redirects. The string prefix check for "192.168" is also flawed as it would allow "192.1689.1.1". Attackers can bypass these controls using alternate IP representations or DNS tricks.

🔄 Data Flow Analysis

  1. Step 1 [SOURCE]: User-controlled URL parameter from HTTP request [LinksController.java:20] → `List<String> linksV2(@RequestParam String url) throws BadRequest{`
  2. Step 2 [FLOW]: URL passed to getLinksV2 with incomplete validation [LinksController.java:21] → `return LinkLister.getLinksV2(url);`
  3. Step 3 [SINK]: After incomplete validation, URL still reaches Jsoup.connect() allowing bypass via localhost, IPv6, metadata IPs, or DNS rebinding [LinkLister.java:32] → `return getLinks(url);`

✅ Recommended Fix

InetAddress addr = InetAddress.getByName(aUrl.getHost()); if (addr.isLoopbackAddress() || addr.isLinkLocalAddress() || addr.isSiteLocalAddress()) { throw new BadRequest("Private IP not allowed"); }

Fix applied to prevent Server-Side Request Forgery (SSRF) - Incomplete Protection

HIGH CWE-79 ✓ AI VERIFIED TRUE POSITIVE

Cross-Site Scripting (XSS)

📍 index.html : Line 73
Full Path: /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/client/index.html

⚠️ Vulnerable Code

<p class="card-text">{{{body}}}</p>

💡 Explanation

The Handlebars template uses triple braces {{{body}}} to render comment body content without HTML escaping. This allows user-submitted comments to be rendered as raw HTML, enabling attackers to inject malicious JavaScript that executes in other users' browsers when they view the comments section.

🔄 Data Flow Analysis

  1. Step 1 [SOURCE]: User input captured in comment text field [index.html:46] → `<input type="text" id="new-comment" class="form-control" placeholder="Comment">`
  2. Step 2 [SINK]: Comment body rendered unescaped using triple braces in Handlebars template, allowing XSS [index.html:73] → `<p class="card-text">{{{body}}}</p>`

✅ Recommended Fix

<p class="card-text">{{body}}</p>

Fix applied to prevent Cross-Site Scripting (XSS)

HIGH CWE-79 ✓ AI VERIFIED FALSE POSITIVE

XSS - jQuery .html()

📍 index.js : Line 2
Full Path: /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/client/js/index.js

⚠️ Vulnerable Code

   1 | $(document).ready(function(){
   2 |   var source = $("#comment-template").html();
   3 |   var template = Handlebars.compile(source);
   4 | 
   5 |   // Add JWT to every request
   6 |   $.ajaxSetup({ beforeSend: function(xhr) {
   7 |     xhr.setRequestHeader('x-auth-token', localStorage.jwt);
   8 |   }});
   9 | 

💡 Explanation

FALSE POSITIVE: Line 2 uses .html() to read the content of a template element (#comment-template), not to write user-controlled data to the DOM. This is reading from a static HTML template, which is then compiled by Handlebars on line 3. Reading content with .html() does not create an XSS vulnerability.

HIGH CWE-79 ✓ AI VERIFIED FALSE POSITIVE

XSS - jQuery .html()

📍 index.js : Line 28
Full Path: /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/client/js/index.js

⚠️ Vulnerable Code

  21 |         $(parent).remove();
  22 |       });
  23 |     });
  24 |   }
  25 | 
  26 |   function fetchComments() {
  27 |     $.get("http://localhost:8080/comments", function(data){
  28 |       $('#comments-container').html('')
  29 |       data.forEach(function(comment){
  30 |         if (comment.body.indexOf("<script>") < 0) {
  31 |           $("#comments-container").append(template(comment));
  32 |         }
  33 |       });
  34 |       setupDeleteCommentHandler();
  35 |     });

💡 Explanation

FALSE POSITIVE: Line 28 uses .html('') to clear/empty the comments container with an empty string literal. This is not setting user-controlled content. The actual comment rendering happens on line 31 using template(comment) with Handlebars, which provides auto-escaping by default. No untrusted data flows into the .html('') call.

HIGH CWE-798 ✓ AI VERIFIED TRUE POSITIVE

Hardcoded Secret in Configuration

📍 application.properties : Line 1
Full Path: /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/src/main/resources/application.properties

⚠️ Vulnerable Code

app.secret=edf10572-880c-4dd9-aaf0-6ec402f678db

💡 Explanation

The application contains a hardcoded secret key (app.secret=edf10572-880c-4dd9-aaf0-6ec402f678db) in the configuration file. This secret appears to be used for JWT token signing based on the jjwt dependencies in pom.xml. Hardcoded secrets in source code or configuration files can be easily extracted by attackers who gain access to the repository, leading to authentication bypass and unauthorized access.

🔄 Data Flow Analysis

  1. Step 1 [SOURCE]: Hardcoded secret stored in application configuration [application.properties:1] → `app.secret=edf10572-880c-4dd9-aaf0-6ec402f678db`
  2. Step 2 [SINK]: Secret exposed in version control and deployments [application.properties:1] → `app.secret=edf10572-880c-4dd9-aaf0-6ec402f678db`

✅ Recommended Fix

Use environment variable: app.secret=${APP_SECRET:default-value-for-dev} and set APP_SECRET in deployment environment

Fix applied to prevent Hardcoded Secret in Configuration

HIGH CWE-798 ✓ AI VERIFIED TRUE POSITIVE

Hardcoded Credentials in Configuration

📍 docker-compose.yml : Line 10
Full Path: /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/docker-compose.yml

⚠️ Vulnerable Code

   3 |   vulnado:
   4 |     build: .
   5 |     ports:
   6 |       - 8080:8080
   7 |     links:
   8 |       - db
   9 |       - internal_site
  10 |     environment:
  11 |       - PGPASSWORD=vulnado
  12 |       - PGDATABASE=vulnado
  13 |       - PGHOST=db:5432
  14 |       - PGUSER=postgres
  15 |     depends_on:
  16 |       - "db"
  17 | 

💡 Explanation

The docker-compose.yml file contains hardcoded database credentials exposed as environment variables. The password 'vulnado' is stored in plaintext at line 11 (PGPASSWORD=vulnado) for the application service. This allows anyone with access to the configuration file to see the database credentials, which could be exploited to gain unauthorized access to the database.

🔄 Data Flow Analysis

  1. Step 1 [SOURCE]: Hardcoded database password set as environment variable [docker-compose.yml:11] → `- PGPASSWORD=vulnado`
  2. Step 2 [SINK]: Credentials exposed in environment configuration block [docker-compose.yml:10] → `environment:`

✅ Recommended Fix

secrets:
  db_password:
    external: true
services:
  vulnado:
    environment:
      - PGPASSWORD_FILE=/run/secrets/db_password
    secrets:
      - db_password

Storing secrets in environment variables or secure vaults keeps them out of source code and version control.

HIGH CWE-798 ✓ AI VERIFIED TRUE POSITIVE

Hardcoded Credentials in Configuration

📍 docker-compose.yml : Line 25
Full Path: /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/docker-compose.yml

⚠️ Vulnerable Code

  18 |   client:
  19 |     build: client
  20 |     ports:
  21 |       - 1337:80
  22 | 
  23 |   db:
  24 |     image: postgres
  25 |     environment:
  26 |       - POSTGRES_PASSWORD=vulnado
  27 |       - POSTGRES_DB=vulnado
  28 | 
  29 |   internal_site:
  30 |     build: internal_site

💡 Explanation

The docker-compose.yml file contains hardcoded database credentials for the PostgreSQL service. The password 'vulnado' is stored in plaintext at line 26 (POSTGRES_PASSWORD=vulnado). This credentials exposure allows anyone with repository or deployment access to obtain the database password, potentially leading to unauthorized database access and data breaches.

🔄 Data Flow Analysis

  1. Step 1 [SOURCE]: Hardcoded PostgreSQL password set as environment variable [docker-compose.yml:26] → `- POSTGRES_PASSWORD=vulnado`
  2. Step 2 [SINK]: Credentials exposed in database service environment configuration [docker-compose.yml:25] → `environment:`

✅ Recommended Fix

secrets:
  postgres_password:
    external: true
services:
  db:
    image: postgres
    environment:
      - POSTGRES_PASSWORD_FILE=/run/secrets/postgres_password
    secrets:
      - postgres_password

Storing secrets in environment variables or secure vaults keeps them out of source code and version control.

HIGH CWE-798 ✓ AI VERIFIED TRUE POSITIVE

Hardcoded Database Password

📍 docker-compose.yml : Line 26
Full Path: /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/docker-compose.yml

⚠️ Vulnerable Code

  19 |     build: client
  20 |     ports:
  21 |       - 1337:80
  22 | 
  23 |   db:
  24 |     image: postgres
  25 |     environment:
  26 |       - POSTGRES_PASSWORD=vulnado
  27 |       - POSTGRES_DB=vulnado
  28 | 
  29 |   internal_site:
  30 |     build: internal_site

💡 Explanation

The docker-compose.yml explicitly defines a hardcoded PostgreSQL database password 'vulnado' at line 26. This is the same finding as #2 but specifically flagged by the pattern matcher for the POSTGRES_PASSWORD variable. Hardcoded credentials in configuration files pose a significant security risk as they can be easily discovered through repository access or deployment artifacts.

🔄 Data Flow Analysis

  1. Step 1 [SOURCE]: Database password hardcoded directly in docker-compose configuration [docker-compose.yml:26] → `- POSTGRES_PASSWORD=vulnado`
  2. Step 2 [SINK]: Password used to initialize PostgreSQL database instance [docker-compose.yml:24] → `image: postgres`

✅ Recommended Fix

# Store password in .env file (excluded from git)
services:
  db:
    image: postgres
    environment:
      - POSTGRES_PASSWORD=${DB_PASSWORD}
# Or use Docker secrets as shown in finding #2

Storing secrets in environment variables or secure vaults keeps them out of source code and version control.

MEDIUM CWE-79 ✓ AI VERIFIED FALSE POSITIVE

XSS - Template expression in HTML context

📍 CommentsController.java : Line 13
Full Path: /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/src/main/java/com/scalesec/vulnado/CommentsController.java

⚠️ Vulnerable Code

   6 | import org.springframework.boot.autoconfigure.*;
   7 | import java.util.List;
   8 | import java.io.Serializable;
   9 | 
  10 | @RestController
  11 | @EnableAutoConfiguration
  12 | public class CommentsController {
  13 |   @Value("${app.secret}")
  14 |   private String secret;
  15 | 
  16 |   @CrossOrigin(origins = "*")
  17 |   @RequestMapping(value = "/comments", method = RequestMethod.GET, produces = "application/json")
  18 |   List<Comment> comments(@RequestHeader(value="x-auth-token") String token) {
  19 |     User.assertAuth(secret, token);
  20 |     return Comment.fetch_all();

💡 Explanation

FALSE POSITIVE: Line 13 uses @Value annotation to inject a configuration property 'app.secret' into a private field. This is standard Spring configuration injection, not XSS. The value is used for JWT token validation (line 19), not rendered in HTML templates.

MEDIUM CWE-79 ✓ AI VERIFIED FALSE POSITIVE

XSS - Template expression in HTML context

📍 LoginController.java : Line 14
Full Path: /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/src/main/java/com/scalesec/vulnado/LoginController.java

⚠️ Vulnerable Code

   7 | import org.springframework.stereotype.*;
   8 | import org.springframework.beans.factory.annotation.*;
   9 | import java.io.Serializable;
  10 | 
  11 | @RestController
  12 | @EnableAutoConfiguration
  13 | public class LoginController {
  14 |   @Value("${app.secret}")
  15 |   private String secret;
  16 | 
  17 |   @CrossOrigin(origins = "*")
  18 |   @RequestMapping(value = "/login", method = RequestMethod.POST, produces = "application/json", consumes = "application/json")
  19 |   LoginResponse login(@RequestBody LoginRequest input) {
  20 |     User user = User.fetch(input.username);
  21 |     if (Postgres.md5(input.password).equals(user.hashedPassword)) {

💡 Explanation

FALSE POSITIVE: Line 14 uses @Value annotation to inject a configuration property 'app.secret' into a private field. This is standard Spring configuration injection, not XSS. The value is used for JWT operations (line 22), not rendered in HTML.

MEDIUM CWE-209 ✓ AI VERIFIED TRUE POSITIVE

Information Exposure Through Error Messages

📍 Comment.java : Line 55
Full Path: /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/src/main/java/com/scalesec/vulnado/Comment.java

⚠️ Vulnerable Code

  48 |         String body = rs.getString("body");
  49 |         Timestamp created_on = rs.getTimestamp("created_on");
  50 |         Comment c = new Comment(id, username, body, created_on);
  51 |         comments.add(c);
  52 |       }
  53 |       cxn.close();
  54 |     } catch (Exception e) {
  55 |       e.printStackTrace();
  56 |       System.err.println(e.getClass().getName()+": "+e.getMessage());
  57 |     } finally {
  58 |       return comments;
  59 |     }
  60 |   }
  61 | 
  62 |   public static Boolean delete(String id) {

💡 Explanation

The printStackTrace() call at line 55 in Comment.java prints detailed stack traces to standard error, which may expose sensitive information about the application's internal structure, file paths, and implementation details to attackers in production environments.

🔄 Data Flow Analysis

  1. Step 1 [SOURCE]: Exception caught during database operation [Comment.java:54] → `} catch (Exception e) {`
  2. Step 2 [SINK]: Stack trace printed to stderr exposing internal details [Comment.java:55] → `e.printStackTrace();`

✅ Recommended Fix

logger.error("Error fetching comments", e); // Use SLF4J or similar

This fix addresses the CWE-209 vulnerability by applying secure coding practices that prevent the identified attack vector.

MEDIUM CWE-209 ✓ AI VERIFIED TRUE POSITIVE

Information Exposure Through Error Messages

📍 Postgres.java : Line 100
Full Path: /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/src/main/java/com/scalesec/vulnado/Postgres.java

⚠️ Vulnerable Code

  93 |        try {
  94 |           pStatement = connection().prepareStatement(sql);
  95 |           pStatement.setString(1, UUID.randomUUID().toString());
  96 |           pStatement.setString(2, username);
  97 |           pStatement.setString(3, md5(password));
  98 |           pStatement.executeUpdate();
  99 |        } catch(Exception e) {
 100 |          e.printStackTrace();
 101 |        }
 102 |     }
 103 | 
 104 |     private static void insertComment(String username, String body) {
 105 |         String sql = "INSERT INTO comments (id, username, body, created_on) VALUES (?, ?, ?, current_timestamp)";
 106 |         PreparedStatement pStatement = null;
 107 |         try {

💡 Explanation

The printStackTrace() call at line 100 in Postgres.java prints detailed stack traces to standard error during user insertion operations, potentially exposing sensitive information about database structure, credentials, and application internals to attackers.

🔄 Data Flow Analysis

  1. Step 1 [SOURCE]: Exception caught during database operation [Postgres.java:99] → `} catch(Exception e) {`
  2. Step 2 [SINK]: Stack trace printed to stderr exposing internal details [Postgres.java:100] → `e.printStackTrace();`

✅ Recommended Fix

logger.error("Error inserting user", e); // Use SLF4J or similar

This fix addresses the CWE-209 vulnerability by applying secure coding practices that prevent the identified attack vector.

MEDIUM CWE-209 ✓ AI VERIFIED TRUE POSITIVE

Information Exposure Through Error Messages

📍 Postgres.java : Line 114
Full Path: /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/src/main/java/com/scalesec/vulnado/Postgres.java

⚠️ Vulnerable Code

 107 |         try {
 108 |             pStatement = connection().prepareStatement(sql);
 109 |             pStatement.setString(1, UUID.randomUUID().toString());
 110 |             pStatement.setString(2, username);
 111 |             pStatement.setString(3, body);
 112 |             pStatement.executeUpdate();
 113 |         } catch(Exception e) {
 114 |             e.printStackTrace();
 115 |         }
 116 |     }
 117 | }

💡 Explanation

The printStackTrace() call at line 114 in Postgres.java prints detailed stack traces to standard error during comment insertion operations, potentially exposing sensitive information about the application's internal structure and database operations to attackers.

🔄 Data Flow Analysis

  1. Step 1 [SOURCE]: Exception caught during database operation [Postgres.java:113] → `} catch(Exception e) {`
  2. Step 2 [SINK]: Stack trace printed to stderr exposing internal details [Postgres.java:114] → `e.printStackTrace();`

✅ Recommended Fix

logger.error("Error inserting comment", e); // Use SLF4J or similar

This fix addresses the CWE-209 vulnerability by applying secure coding practices that prevent the identified attack vector.

MEDIUM CWE-209 ✓ AI VERIFIED TRUE POSITIVE

Information Exposure Through Error Messages

📍 User.java : Line 34
Full Path: /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/src/main/java/com/scalesec/vulnado/User.java

⚠️ Vulnerable Code

  27 |   public static void assertAuth(String secret, String token) {
  28 |     try {
  29 |       SecretKey key = Keys.hmacShaKeyFor(secret.getBytes());
  30 |       Jwts.parser()
  31 |         .setSigningKey(key)
  32 |         .parseClaimsJws(token);
  33 |     } catch(Exception e) {
  34 |       e.printStackTrace();
  35 |       throw new Unauthorized(e.getMessage());
  36 |     }
  37 |   }
  38 | 
  39 |   public static User fetch(String un) {
  40 |     Statement stmt = null;
  41 |     User user = null;

💡 Explanation

The printStackTrace() call at line 34 in User.java prints detailed stack traces during JWT authentication failures, potentially exposing sensitive information about the application's security implementation, JWT library details, and internal structure to attackers.

🔄 Data Flow Analysis

  1. Step 1 [SOURCE]: Exception caught during JWT authentication [User.java:33] → `} catch(Exception e) {`
  2. Step 2 [SINK]: Stack trace printed to stderr exposing internal details [User.java:34] → `e.printStackTrace();`

✅ Recommended Fix

logger.error("Authentication failed", e); // Use SLF4J or similar

This fix addresses the CWE-209 vulnerability by applying secure coding practices that prevent the identified attack vector.

MEDIUM CWE-209 ✓ AI VERIFIED TRUE POSITIVE

Information Exposure Through Error Messages

📍 User.java : Line 58
Full Path: /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/src/main/java/com/scalesec/vulnado/User.java

⚠️ Vulnerable Code

  51 |         String user_id = rs.getString("user_id");
  52 |         String username = rs.getString("username");
  53 |         String password = rs.getString("password");
  54 |         user = new User(user_id, username, password);
  55 |       }
  56 |       cxn.close();
  57 |     } catch (Exception e) {
  58 |       e.printStackTrace();
  59 |       System.err.println(e.getClass().getName()+": "+e.getMessage());
  60 |     } finally {
  61 |       return user;
  62 |     }
  63 |   }
  64 | }

💡 Explanation

The printStackTrace() call at line 58 in User.java prints detailed stack traces during user fetch operations, potentially exposing sensitive information about database structure, connection details, and application internals to attackers monitoring error outputs.

🔄 Data Flow Analysis

  1. Step 1 [SOURCE]: Exception caught during database operation [User.java:57] → `} catch (Exception e) {`
  2. Step 2 [SINK]: Stack trace printed to stderr exposing internal details [User.java:58] → `e.printStackTrace();`

✅ Recommended Fix

logger.error("Error fetching user", e); // Use SLF4J or similar

This fix addresses the CWE-209 vulnerability by applying secure coding practices that prevent the identified attack vector.

MEDIUM CWE-209 ✓ AI VERIFIED TRUE POSITIVE

Information Exposure Through Error Messages

📍 Cowsay.java : Line 24
Full Path: /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/src/main/java/com/scalesec/vulnado/Cowsay.java

⚠️ Vulnerable Code

  17 |       BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
  18 | 
  19 |       String line;
  20 |       while ((line = reader.readLine()) != null) {
  21 |         output.append(line + "\n");
  22 |       }
  23 |     } catch (Exception e) {
  24 |       e.printStackTrace();
  25 |     }
  26 |     return output.toString();
  27 |   }
  28 | }

💡 Explanation

The printStackTrace() method at line 24 in Cowsay.java prints the full stack trace to the console/logs. This can expose sensitive information about the application's internal structure, file paths, and potentially security-relevant details to attackers who have access to logs or error output. Stack traces should be logged using a proper logging framework with appropriate log levels and never exposed to end users.

🔄 Data Flow Analysis

  1. Step 1 [SOURCE]: Exception caught during process execution [Cowsay.java:23] → `} catch (Exception e) {`
  2. Step 2 [SINK]: Stack trace printed to standard error, exposing internal details [Cowsay.java:24] → `e.printStackTrace();`

✅ Recommended Fix

} catch (Exception e) {
  logger.error("Error executing cowsay command", e);
}

This fix addresses the CWE-209 vulnerability by applying secure coding practices that prevent the identified attack vector.

LOW CWE-20 ✓ AI VERIFIED FALSE POSITIVE

Potential data flow sink

📍 Cowsay.java : Line 17
Full Path: /home/ubuntu/sast-webapp/uploads/tmpvzwexh5m/src/main/java/com/scalesec/vulnado/Cowsay.java

⚠️ Vulnerable Code

  10 |     System.out.println(cmd);
  11 |     processBuilder.command("bash", "-c", cmd);
  12 | 
  13 |     StringBuilder output = new StringBuilder();
  14 | 
  15 |     try {
  16 |       Process process = processBuilder.start();
  17 |       BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
  18 | 
  19 |       String line;
  20 |       while ((line = reader.readLine()) != null) {
  21 |         output.append(line + "\n");
  22 |       }
  23 |     } catch (Exception e) {
  24 |       e.printStackTrace();

💡 Explanation

FALSE POSITIVE: Line 17 creates a BufferedReader to read the OUTPUT stream from a child process (cowsay command). This is not a vulnerability - it's the standard way to read output from a subprocess. The actual security issue in this code is the Command Injection vulnerability at line 9 where user input is concatenated into a shell command without sanitization, but that's not what this finding is flagging. Reading from process.getInputStream() is safe and necessary.