From 98f90a379e387bd40b8877299130801cafc4fd37 Mon Sep 17 00:00:00 2001 From: saidai-bhuvanesh Date: Thu, 6 Aug 2026 05:56:01 +0000 Subject: [PATCH] fix: validate country input to prevent SSRF vulnerability - Added ALLOWED_COUNTRIES whitelist with valid Adzuna country codes - Added getValidCountry() function to validate user input - Country parameter now validated before use in API URL - Falls back to default country if invalid input provided --- backend/controllers/jobController.js | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/backend/controllers/jobController.js b/backend/controllers/jobController.js index 7c759468..2e23c980 100644 --- a/backend/controllers/jobController.js +++ b/backend/controllers/jobController.js @@ -7,10 +7,24 @@ const ADZUNA_API_KEY = process.env.ADZUNA_API_KEY; const ADZUNA_COUNTRY = process.env.ADZUNA_COUNTRY || "in"; const CACHE_TTL_MS = 24 * 60 * 60 * 1000; +// Whitelist of valid country codes supported by Adzuna API +const ALLOWED_COUNTRIES = new Set(["in", "us", "gb", "au", "ca", "de", "fr", "nl", "be", "at", "pl", "es", "it", "ch", "sg"]); + // The Jobs feature is optional: without Adzuna credentials it stays dormant // instead of crashing the server or spamming failed API calls. const isAdzunaConfigured = () => Boolean(ADZUNA_APP_ID && ADZUNA_API_KEY); +/** + * Validates and returns a safe country code. + * Falls back to default if invalid. + */ +function getValidCountry(country) { + if (country && ALLOWED_COUNTRIES.has(country.toLowerCase())) { + return country.toLowerCase(); + } + return ADZUNA_COUNTRY; +} + async function fetchFromAdzuna(role, country = ADZUNA_COUNTRY) { const url = `https://api.adzuna.com/v1/api/jobs/${country}/search/1`; const { data } = await axios.get(url, { @@ -53,7 +67,7 @@ exports.getJobs = async (req, res) => { .select("role"); const role = req.query.role || latestSession?.role || "software engineer"; - const country = req.query.country || ADZUNA_COUNTRY; + const country = getValidCountry(req.query.country); const cacheKey = `${role.toLowerCase()}|${country}`; const cached = await JobCache.findOne({ cacheKey });