In this post, we’ll go through and solve all the challenges from the Secure Code Review Challenges repository by dub-flow. These exercises are designed to test and improve your ability to spot and understand common security issues in source code. Whether you’re just getting started or sharpening your review skills, this walkthrough will guide you step by step through each challenge.

challenge-01
We are given the source code of a web application written in Python.
from flask import Flask, request, redirect, url_for
import logging
app = Flask(__name__)
logging.basicConfig(level=logging.INFO)
def is_authenticated_user():
# This function checks if the user is authenticated and is omitted for brevity
pass
@app.route('/')
def home():
if not is_authenticated_user():
logging.info('Unauthorized access attempt.')
return redirect(url_for('login'))
redirect_url = request.args.get('redirect_url')
if redirect_url:
logging.info(f'Redirecting to: {redirect_url}')
return redirect(redirect_url)
return 'Welcome to the home page!'
@app.route('/login')
def login():
# Simulated login page
return 'Login Page - User authentication goes here.'
if __name__ == '__main__':
app.run(debug=False)
This is a web application built using the Flask framework. It defines a function called is_authenticated_user
, which is omitted from the code since it is not relevant for this context. The application has tho main routes: the root route (/
), which serves as the home page, and the /login
route, which simulates a login page for user authentication.
The key logic is within the home route. If the user is not authenticated, the aplication logs an unauthorized acces attempt and redirects the user to the login page. If the user is authenticated and a redirect_url
parameter is present in the request, the application logs the redirection and forwards the user to that specified URL. Otherwhise, ti simply returns a welcome message.
challenge-02
We are given th source code of a web application written in JavaScript.
const express = require('express');
const axios = require('axios');
const app = express();
app.get('/profile', (req, res) => {
console.log('Received request for /profile');
// Simulated profile data
const profileData = {
name: 'John Doe',
role: 'Developer'
};
res.json(profileData);
console.log('Sent profile data response');
});
app.get('/fetch-data', async (req, res) => {
const url = req.query.url;
console.log(`Received request for /fetch-data with URL: ${url}`);
try {
const response = await axios.get(url);
res.send(response.data);
console.log(`Data fetched and sent for URL: ${url}`);
} catch (error) {
console.error(`Error fetching data from URL: ${url}`, error);
res.status(500).send('Error fetching data');
}
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});
This is a web application built using the Express framework. It defines two main routes: /profiles
, which returns simulated user profile data as JSON, and /fetch-data
, which accepts a url
parameter via the query string and fetches data from that URL using the Axios library.
The key issue lies within /fetch-data
route. It takes the url
parameter directly from the user request without any validation or restrictions and uses it to make and HTTP GET request. This allows an attacker to supply aribitrary URLs, potentially causing the server to request internal or sensitive resources whithin a private network, a vulnerability known as Server-Side Request Forgery (SSRF). As a result, the attacker can exploit this to access protected internal services or malicious endpoints.
To exploit this, we can use the curl command and send the url parameter with any URL we want in the request. We can see that the server fetches and returns the data from that URL. Unlike an open redirect, if we point it to an internal address, the server will actually resolve and fetch it. In this example, I didn’t test that, but it is possible.
$ curl http://localhost:3000/fetch-data\?url\=https://blog.lukas.re/ <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="generator" content="Hugo 0.138.0"> <title>Lukas Blog</title><link rel="stylesheet" href="https://blog.lukas.re/css/colors-default-dark.css"> <link rel="stylesheet" href="https://blog.lukas.re/css/style.css"> <link rel="alternate" type="application/rss+xml" href="https://blog.lukas.re/index.xml" title="Lukas Blog"> </head> <body> <div class="site-content"> <header> <div class="header-container"> <div class="site-header"> <a class="site-header" href="https://blog.lukas.re/">Lukas Blog</a> </div> <div class="site-nav"> <nav aria-label="Site menu" class="site-nav"><a class="nav-item first" href="/post/">posts</a><a class="nav-item last" href="/about/">about</a> </nav> </div> </div> </header> <main class="content"> <img alt="Ellingson Mineral Company" style="display:block;margin-left:auto;margin-right:auto;max-width:100%;height:auto;" src="images/i.png"> <p><strong>Welcome to my blog!</strong></p> <p>Here you’ll find content about cybersecurity, AI, personal projects, and more.</p> </main> <footer><div class="footer-container"> <div class="h-card bio"> <p> <a class="u-url" href="https://blog.lukas.re/">Lukas Blog</a> created by <img class="u-photo" alt="" src="https://blog.lukas.re/images/i.jpg"> <span class="p-name" rel="me">Lukas Gaete</span> (<span class="u-pronoun">they</span>/<span class="u-pronoun">them</span> pronouns. </p> </div><div class="footer-text footer-right"> <p> Stay focus 🧠. </p> </div></div> <div class="h-card social"> <a class="u-url" rel="me" aria-label="email" href="/cdn-cgi/l/email-protection#026360776c66366c764272706d766d6c2c6f67"><span class="social-icon" ></span></a> <a class="u-url" rel="me" aria-label="github" href="https://github.com/abund4nt"><span class="social-icon" ></span></a> </div> </footer> </div> <script data-cfasync="false" src="/cdn-cgi/scripts/5c5dd728/cloudflare-static/email-decode.min.js"></script></body>