Starting the challenge and reading the source code of server.js, you can observe that the application uses prepared queries ‘almost’ everywhere in the code.
For example :
Register endpoint
app.post('/api/register', async (req, res) => {
try {
const { username, password } = req.body;
if (!username || !password) {
return res.status(400).json({ error: 'Username and password are required' });
}
const hashedPassword = await bcrypt.hash(password, 10);
db.run('INSERT INTO users (username, password, role) VALUES (?, ?, ?)',
[username, hashedPassword, 'user'],
function(err) {
if (err) {
if (err.message.includes('UNIQUE constraint failed')) {
return res.status(400).json({ error: 'Username already exists' });
}
return res.status(500).json({ error: err.message });
}
Tasks endpoint
app.get('/api/tasks', authenticateToken, authorizeRole('admin'), (req, res) => {
let query = 'SELECT * FROM tasks';
let params = [];
if (req.user.role !== 'admin') {
query += ' WHERE user_id = ?';
params.push(req.user.id);
}
db.all(query, params, (err, tasks) => {
if (err) {
return res.status(500).json({ error: err.message });
}
res.json(tasks);
});
});
However, that’s not the case for the Login endpoint.
app.post('/api/login', (req, res) => {
const { username, password } = req.body;
if (!username || !password) {
return res.status(400).json({ error: 'Username and password are required' });
}
db.exec(`SELECT last_login FROM users WHERE username = '${username}' ;`, (err) => {
if (err) {
return res.status(500).json({ error: err.message });
}
When querying the last_login column from the database, the user input is directly embedded into the SQL string. That’s clearly vulnerable to SQL Injection.

Now, because the application is using db.exec, this is considered a Stacked Queries SQL Injection.
Which basically means you can terminate the current query and start another one by using ; :
'; INSERT INTO users(username,password,role) VALUES ('yonkoadmin', 'password', 'admin') --
But you can’t simply do that, because of the bcrypt.compare in the Login endpoint :
app.post('/api/login', (req, res) => {
const { username, password } = req.body;
if (!username || !password) {
return res.status(400).json({ error: 'Username and password are required' });
}
db.exec(`SELECT last_login FROM users WHERE username = '${username}' ;`, (err) => {
if (err) {
return res.status(500).json({ error: err.message });
}
db.get('SELECT * FROM users WHERE username = ?', [username], async (err, user) => {
if (err) {
return res.status(500).json({ error: err.message });
}
if (!user) {
return res.status(401).json({ error: 'Invalid credentials' });
}
const validPassword = await bcrypt.compare(password, user.password);