Fix high and medium security vulnerabilities
CSRF: upgrade session cookie sameSite from 'lax' to 'strict'. Rate limiting: login endpoint now blocks an IP after 10 failed attempts in a 15-minute window; resets on success. In-memory, no new dependency. SESSION_SECRET: server exits at startup when NODE_ENV=production and SESSION_SECRET is unset. docker-compose.yml updated to pass it via env; .env.example added with generation instructions. Security headers: add X-Content-Type-Options, X-Frame-Options, and Referrer-Policy to all responses. Sensitive data: routing_number and account_number are now omitted from GET /api/account/:id responses for non-admin users. Image size: logo upload capped at 512 KB in the account PUT handler. Amount validation: checks (POST/PUT) and deposit items (POST/PUT) now reject non-finite and non-positive amounts. QBO import: uploaded file is rejected if its MIME type is not text or a known CSV variant.
This commit is contained in:
+18
-2
@@ -49,6 +49,14 @@ router.post('/', (req, res) => {
|
||||
if (!isEditorForAccount(req.session, parseInt(account_id, 10))) {
|
||||
return res.status(403).json({ error: 'Write access required.' });
|
||||
}
|
||||
if (Array.isArray(items)) {
|
||||
for (const item of items) {
|
||||
const a = parseFloat(item.amount);
|
||||
if (!isFinite(a) || a <= 0) {
|
||||
return res.status(400).json({ error: 'Each deposit item amount must be a positive number.' });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const insert = db.transaction(() => {
|
||||
const result = db.prepare(`
|
||||
@@ -76,7 +84,7 @@ router.post('/', (req, res) => {
|
||||
item.bank_no || null,
|
||||
item.payee || null,
|
||||
item.memo || null,
|
||||
parseFloat(item.amount) || 0,
|
||||
parseFloat(item.amount),
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -98,6 +106,14 @@ router.put('/:id', (req, res) => {
|
||||
|
||||
const { deposit_date, currency, coin, cash_back, items } = req.body;
|
||||
if (!deposit_date) return res.status(400).json({ error: 'deposit_date is required.' });
|
||||
if (Array.isArray(items)) {
|
||||
for (const item of items) {
|
||||
const a = parseFloat(item.amount);
|
||||
if (!isFinite(a) || a <= 0) {
|
||||
return res.status(400).json({ error: 'Each deposit item amount must be a positive number.' });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const update = db.transaction(() => {
|
||||
db.prepare(`
|
||||
@@ -124,7 +140,7 @@ router.put('/:id', (req, res) => {
|
||||
item.bank_no || null,
|
||||
item.payee || null,
|
||||
item.memo || null,
|
||||
parseFloat(item.amount) || 0,
|
||||
parseFloat(item.amount),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user