GOwasp simulates a vulnerable web application built with Go and Vue.js. It showcases some of the most common security flaws found in modern web applications, based on the OWASP Top 10 list.
The project encourages hands-on learning:
- Exploit each vulnerability.
- Understand the risk.
- Apply the fix.
To run the app, in the root directory type:
make rIf you want to run it with Docker π³ locally, use:
make drOr without building it locally:
docker run -p 8083:8083 ghcr.io/manuelarte/gowasp:v0.0.6You can find the Swagger UI in swagger/index.html.
Once the application is up and running, you can begin by exploring its core features.
Start by navigating to the signup page. Try creating a user account with the following credentials:
username: test
password: testAfter logging in or creating an account, youβll be redirected to the welcome page. This page displays an introductory blog post along with links to the latest entries. Click on one of the recent posts to continue exploring.
Clicking a post takes you to its detail page, where you can read the content, view existing comments, and submit your own.
Note
Try to submit a comment like:
Very nice post!
Now that you've explored the basic functionality, it is time to dive into the fun part: hacking the application.
Let's explore different vulnerabilities by exploiting some of the functionalities that this app provides:
We'll start by exploring vulnerabilities in the /api/users/signup endpoint. Specifically, you'll investigate the following issues:
Tip
Use the provided HTTP client file users-signup.http, to follow along and test each case.
In users/service.go, the password policy currently allows any value with more than four characters (#1. Scenario).
To strengthen this, update the logic to enforce the following rules:
- Require a minimum of 8 characters (and a maximum of 256).
- Include at least one non-alphanumeric character.
After applying these changes, verify the new password validation behavior.
π€ Weak hash algorithm
For a detailed explanation of this vulnerability, see the Weak Hashing Algorithm Vulnerability.
To explore this issue, follow the steps in #2. Scenario:
- Submit a signup request and extract the generated MD5 hash.
- Use a tool like md5-encrypt-decrypt to estimate how quickly an attacker can reverse the hash.
- Confirm that hashing the same password always produces the same result.
Important
Avoid outdated hashing algorithms like MD5. They offer weak protection against brute-force attacks.
To improve password security, the best solution is to use up-to date hashing algorithms, like bcrypt, scrypt or PBKDF2.
- Replace MD5 with bcrypt.
- Generate a unique salt for each user.
- Re-run #2 Scenarioand verify that the same password produces different hashes.
π Mass Assignment
For a detailed explanation of this vulnerability, see the OWASP Mass Assignment Cheat Sheet.
We are going to exploit the vulnerability related to the API endpoint /api/users/signup.
When inspecting the login response, youβll notice a field named isAdmin.
The HTML signup form doesnβt expose this field, but what happens if you include it directly in the API request?
Try sending a crafted request that sets isAdmin to true and observe the outcome.
We are going to exploit the vulnerabilities related to the endpoint to log in a user in /api/users/login. The vulnerability that we are going to check is:
An HTTP client is provided in users-login.http to follow along.
As you can see in users repository.go, in the Login method, the query is created by string concatenation.
ππ’ SQL injection
For a detailed explanation of this vulnerability, see the OWASP SQL Injection Cheat Sheet.
Try to exploit this query concatenation by concatenating an always true SQL statement (something like OR '1'='1'-).
The goal is to avoid the execution of the password clause (maybe by injecting a comment (--) to comment out the rest of the query)
Important
Never concatenate strings in a query.
Once you're logged in, you are redirected to the Welcome page. There you can see an Intro Post.
The vulnerabilities that we are going to check in this scenario:
To follow along, check posts.http
If you open the network tab developer console in your web browser (by default F12), and refresh the welcome page, the program makes a call to /posts?name=intro.txt.
Let's check how the GetStaticPostFileByName method is implemented in posts controller.
We can see that we are using os.Open:
file, err := os.Open(fmt.Sprintf("./resources/posts/%s", name))- What would happen in we change the name query parameter to point to a different file in a different location?, maybe we could try with ../internal/private.txt
- Try to also display /etc/passwdfile content.
To solve this issue for this scenario, we could validate the user input, and avoid path traversal with functions like os.Root
Important
Always validate user input.
The vulnerabilities we are going to check here:
For a detailed explanation of this vulnerability, see the OWASP Authorization Cheat Sheet.
In Scenario 1 of the http tool post_comments.http, you can create a comment for a post.
However, the payload includes postId and userId fields that you can manipulate.
By modifying these values, you can create comments as any user on any post.
To fix this vulnerability, consider these approaches:
- Override the userIdandpostIdfields in the payload with trusted values (the user id coming from the session cookie and thepostIdcoming from the url).
- (Preferred) Define a dedicated struct that accepts only valid fields, similar to the UserSignupstruct, to prevent unauthorized data injection.
For a detailed explanation of this vulnerability, see the Cross Site Request Forgery Prevention Cheat Sheet.
The post-comments endpoint lacks protection against CSRF attacks. Verify this by following these steps:
- Log in to the application using your browser.
- Open price-win.html in the same browser.
- Click the rewards button.
- Visit /post/2/comments and observe the result.
This exploit combines vulnerabilities from both CSRF and HTML template injection.
Prevent CSRF attacks by adding a CSRF token cookie to requests and validating that the token in the JSON payload matches the cookie value. In the file AddComment.vue the token appears as:
<script setup lang="ts">
const props = defineProps({
    ...
    csrf: {
        type: String,
        required: true,
        validator: (v: string, _) => v.length > 0,
    },
})
...Implement validation to ensure the csrf value from the JSON payload matches the csrf cookie sent in the request.
After applying the fix, restart the application and confirm that creating comments via the win price button no longer works.
ππ HTML template injection
Earlier, you encountered a template injection vulnerability.
Run the #Scenario 2 HTTP requests that attempts to inject <script> tag in your comment.
To solve this, remember to always escape and validate user input to prevent injection attacks.
In general, frameworks like Gin Framework provide built-in protection against this vulnerability.
In this project, we are using Vue v-html bind to render raw HTML.
Check /posts/id.vue to see how to render HTML content without escaping it.