fix: resolve SonarQube hotspots for upload size and X-Powered-By
SonarQube Analysis / sonarqube (pull_request) Successful in 7m11s
Tests / backend-unit (pull_request) Successful in 2m18s
Tests / backend-integration (pull_request) Successful in 2m28s
Tests / frontend-e2e (pull_request) Failing after 59s

- S5693: MAX_IMAGE_BYTES was 8 * 1024 * 1024 (8,388,608), just over the
  8,000,000-byte ceiling the rule treats as safe, so the hotspot on the
  multer storage config never cleared. Use 8_000_000.
- S5689: Express advertises its stack in X-Powered-By by default, which
  tells an attacker what to aim exploits at. Disable the header.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-14 17:18:42 -05:00
co-authored by Claude Opus 5
parent 9e4adb0586
commit ab1024a1b6
2 changed files with 6 additions and 1 deletions
+3
View File
@@ -13,6 +13,9 @@ import shippingAddressesRouter from './routes/shippingAddresses';
import { attachCustomer } from './middleware/customerAuth'; import { attachCustomer } from './middleware/customerAuth';
const app = express(); const app = express();
// Express advertises itself in X-Powered-By by default, which hands an
// attacker the server stack for free when picking exploits to try.
app.disable('x-powered-by');
app.set('trust proxy', 1); app.set('trust proxy', 1);
app.use('/webhooks/paypal', express.json(), cartCheckoutWebhookRouter); app.use('/webhooks/paypal', express.json(), cartCheckoutWebhookRouter);
+3 -1
View File
@@ -13,7 +13,9 @@ const UPLOADS_DIR = process.env.UPLOADS_DIR || '/app/uploads';
// multipart body: image count, bytes per image, and the small text fields // multipart body: image count, bytes per image, and the small text fields
// (name/description/price) that accompany them. // (name/description/price) that accompany them.
const MAX_IMAGES_PER_REQUEST = 6; const MAX_IMAGES_PER_REQUEST = 6;
const MAX_IMAGE_BYTES = 8 * 1024 * 1024; // 8 MB, not 8 MiB — this is the ceiling S5693 treats as safe, and 8 * 1024 *
// 1024 sits just over it. Plenty for a product photo either way.
const MAX_IMAGE_BYTES = 8_000_000;
const MAX_TEXT_FIELDS = 8; const MAX_TEXT_FIELDS = 8;
const MAX_TEXT_FIELD_BYTES = 64 * 1024; const MAX_TEXT_FIELD_BYTES = 64 * 1024;