Overview
Affected Versions
Parse Server 9.5.x and earlier (9.6.0-alpha.29 fixes) and Parse Server 8.6.x and earlier (8.6.49 fixes); affected: before 9.6.0-alpha.29 and before 8.6.49.
Code Fix Example
// Node.js (Express) example showing vulnerable vs fixed signup handling
const express = require('express');
const app = express();
app.use(express.json());
// In-memory user store (demo only)
const users = [];
function generateId() { return 'u_' + Math.random().toString(36).slice(2, 9); }
function hashPassword(pw) { return 'hash(' + pw + ')'; }
// ----------------- Vulnerable pattern (allowed with empty authData) -----------------
app.post('/signup-vulnerable', (req, res) => {
const { username, password, authData } = req.body;
// Vulnerable: any presence of authData triggers provider flow; even empty object ({}).
if (authData) {
// Sign up via external provider data without validating credentials
const user = { id: generateId(), authData };
users.push(user);
// pretend session establishment
req.session = { userId: user.id };
return res.json({ ok: true, userId: user.id, mode: 'vulnerable-auth' });
}
// Fallback: require credentials
if (!username || !password) {
return res.status(400).json({ error: 'Credentials required' });
}
const user = { id: generateId(), username, passwordHash: hashPassword(password) };
users.push(user);
req.session = { userId: user.id };
res.json({ ok: true, userId: user.id, mode: 'credentials' });
});
// ----------------- Fixed pattern (empty authData treated as absent) -----------------
app.post('/signup-fixed', (req, res) => {
const { username, password, authData } = req.body;
// Fix: treat empty or non-actionable authData as absent
const hasValidAuthData = !!authData && Object.keys(authData).length > 0;
if (hasValidAuthData) {
// Sign up via provider data
const user = { id: generateId(), authData };
users.push(user);
req.session = { userId: user.id };
return res.json({ ok: true, userId: user.id, mode: 'provider' });
}
// No valid authData: require credentials
if (!username || !password) {
return res.status(400).json({ error: 'Credentials required' });
}
const user = { id: generateId(), username, passwordHash: hashPassword(password) };
users.push(user);
req.session = { userId: user.id };
res.json({ ok: true, userId: user.id, mode: 'credentials' });
});
// Start server (for demonstration)
app.listen(3000, () => {
console.log('Demo server running on http://localhost:3000');
});