Overview
Affected Versions
Parse Server versions prior to 8.6.67 and prior to 9.7.0-alpha.11 (i.e., < 8.6.67 and < 9.7.0-alpha.11).
Code Fix Example
Vulnerable pattern (conceptual, Node.js/Express inspired):
// Vulnerable: dynamic dispatch based on client-provided name, with separate validators that are not guaranteed to align with the chosen handler
const handlers = {
getUserData: (req, res) => { res.json({ data: 'secret' }); }
};
const validators = {
getUserData: (req, res, next) => {
if (!req.user) return res.status(401).send('Unauthorized');
next();
}
};
app.get('/cloudfunc/:name', (req, res, next) => {
const name = req.params.name; // attacker-controlled string
const handler = handlers[name]; // dynamic lookup via name
const validator = validators[name]; // could be undefined or mismatched
if (validator) {
validator(req, res, () => handler(req, res));
} else if (handler) {
handler(req, res);
} else {
res.status(404).send('Not found');
}
});
// This pattern can allow bypass if an attacker supplies a name that traverses prototype chains or bypasses ownership checks via misaligned validator/handler mappings.
----------------------------------------
Fixed pattern (explicit, safe mapping):
// Safe: use a strict, whitelisted map of allowed operations with a single source of truth for validator + handler binding
const WHITELIST = {
getUserData: {
handler: (req, res) => { res.json({ data: 'secret' }); }
}
};
// Centralized, explicit authorization enforcement
const requireUser = (req, res, next) => {
if (!req.user) return res.status(401).send('Unauthorized');
next();
};
app.get('/cloudfunc/:name', (req, res) => {
const name = req.params.name;
const entry = WHITELIST[name];
if (!entry) return res.status(404).send('Not found');
// Always enforce authorization first, using a single, explicit chain
return requireUser(req, res, () => entry.handler(req, res));
});
// The fix uses a whitelist and explicit authorization middleware instead of dynamic, prototype-based resolution.