Remerge dev to master - #14
Conversation
[skip ci]
…re correct ip in logs
…dd warnings for fungi and pest-species
…bility (temporary)
…dless of name change or missing
…s and return id/pass in /identify
| const cleanIP = realIP | ||
| .replace(/^::ffff:/, '') | ||
| .replace(/:\d+[^:]*$/, '') |
Check failure
Code scanning / CodeQL
Polynomial regular expression used on uncontrolled data High
| scientificNameIdObject = await axios | ||
| .get(url, { | ||
| timeout: 3000, | ||
| headers: { | ||
| 'Accept-Encoding': 'gzip', | ||
| 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:145.0) Gecko/20100101 Firefox/145.0' | ||
| } | ||
| }) |
Check failure
Code scanning / CodeQL
Server-side request forgery Critical
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 8 months ago
To resolve this SSRF vulnerability, user input for sciNameId (from the /cachetaxon/id/* endpoint) should be validated prior to building an outgoing request URL. The safest approach is to only allow expected, well-formed taxon IDs: for example, restrict to numeric or strictly alphanumeric values, matching the anticipated identifier format. Reject or sanitize any input that could allow path traversal, special characters, or other manipulations.
- Validate
taxonIdin the route handler: Add a check to verify the incoming taxon ID only matches allowed patterns (e.g., numbers, or letters/numbers/underscores). If the validation fails, return a 400 Bad Request. - Optionally, validate in
getNameas well: As extra defense, you can also validatesciNameIdbefore constructing the remote API URL.
Changes to make:
- In
/cachetaxon/id/*route handler, validate extractedtaxonIdusing a regular expression. - If validation fails, return HTTP 400 and do not make backend requests.
- You may use a well-known library like
validator(if allowed), or Node's own regex, as seen in provided imports.
Only changes within server.js are required.
| @@ -1955,6 +1955,11 @@ | ||
| app.get("/cachetaxon/id/*", cacheLimiter, authenticateAdminToken, async (req, res) => { | ||
| try { | ||
| let taxonId = decodeURI(req.originalUrl.replace("/cachetaxon/id/", "")); | ||
| // Only allow strictly alphanumeric (plus underscore/dash), 1-50 chars -- adjust as needed for real taxon IDs | ||
| if (!taxonId.match(/^[a-zA-Z0-9_-]{1,50}$/)) { | ||
| res.status(400).json({ error: "Invalid taxonId." }); | ||
| return; | ||
| } | ||
| let name = await getName(taxonId, "", true); | ||
| res.status(200).json(name); | ||
| } catch (error) { |
| } | ||
| }) | ||
| .catch((error) => { | ||
| console.log(`Failed to get GBIF names for ${nameResult.scientificName}:`, error.message); |
Check failure
Code scanning / CodeQL
Use of externally-controlled format string High
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 8 months ago
To prevent user-controlled input from being interpreted as a format string, do not embed tainted input directly within template literals or string concatenations that are intended as the format string argument in logging functions. Instead, use a static format string with a placeholder (such as %s) and pass the potentially unsafe value as a separate argument.
Specifically, for the problematic log call at line 901:
Edit:
- Change
console.log(Failed to get GBIF names for ${nameResult.scientificName}:, error.message); - To:
console.log('Failed to get GBIF names for %s:', nameResult.scientificName, error.message);
This ensures that nameResult.scientificName is treated as a value rather than a formatting string.
Only line 901 requires changing in the code you've been shown; there are no required import changes or new method/variable definitions.
| @@ -898,7 +898,7 @@ | ||
| } | ||
| }) | ||
| .catch((error) => { | ||
| console.log(`Failed to get GBIF names for ${nameResult.scientificName}:`, error.message); | ||
| console.log('Failed to get GBIF names for %s:', nameResult.scientificName, error.message); | ||
| return null; | ||
| }); | ||
|
|
| } | ||
| } | ||
| } catch (error) { | ||
| console.log(`Error fetching GBIF names for ${nameResult.scientificName}:`, error.message); |
Check failure
Code scanning / CodeQL
Use of externally-controlled format string High
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 8 months ago
To fix this problem, we need to ensure that any user-provided value is not interpreted as a format string by console.log. The best practice is to use a static format string with explicit %s substitution patterns, and pass tainted/user-supplied data as additional parameters to avoid format string confusion. In this particular case, the correct fix is to change the template literal used as the first argument (`Error fetching GBIF names for ${nameResult.scientificName}:`) to a static string with a %s substitution, so the log call becomes:
console.log("Error fetching GBIF names for %s:", nameResult.scientificName, error.message);as opposed to pushing user data directly into the format string. There is no need to import any new libraries to implement this change. No additional methods or definitions are required.
| @@ -932,7 +932,7 @@ | ||
| } | ||
| } | ||
| } catch (error) { | ||
| console.log(`Error fetching GBIF names for ${nameResult.scientificName}:`, error.message); | ||
| console.log("Error fetching GBIF names for %s:", nameResult.scientificName, error.message); | ||
| } | ||
| } | ||
|
|
| } | ||
| }) | ||
| .catch((error) => { | ||
| console.log(`Failed to get Swedish name for ${nameResult.scientificName}:`, error.message); |
Check failure
Code scanning / CodeQL
Use of externally-controlled format string High
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 8 months ago
To fix this vulnerability, adjust the logging so that the template string containing the user-supplied value isn't directly passed as a format string to console.log. Instead, use a constant format string with a %s (string) placeholder, and then pass the potentially untrusted value as a separate argument. Specifically, on line 952 of server.js, change this:
console.log(`Failed to get Swedish name for ${nameResult.scientificName}:`, error.message);to:
console.log("Failed to get Swedish name for %s:", nameResult.scientificName, error.message);This ensures that user-controlled input does not influence the format string passed to console.log, addressing CodeQL's concern. No new imports or methods are needed; just a simple code edit.
| @@ -949,7 +949,7 @@ | ||
| } | ||
| }) | ||
| .catch((error) => { | ||
| console.log(`Failed to get Swedish name for ${nameResult.scientificName}:`, error.message); | ||
| console.log("Failed to get Swedish name for %s:", nameResult.scientificName, error.message); | ||
| return null; | ||
| }); | ||
|
|
| } | ||
| }) | ||
| .catch((error) => { | ||
| console.log(`Failed to get Wikipedia names for ${nameResult.scientificName}:`, error.message); |
Check failure
Code scanning / CodeQL
Use of externally-controlled format string High
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 8 months ago
To mitigate this format string vulnerability, we should avoid placing untrusted data directly into a format string supplied to console.log when additional arguments are provided. The best practice is to use a format specifier (%s) in the log string and pass untrusted data as subsequent arguments, rather than embedding it directly within the template literal. This fixes the issue by ensuring console.log treats the user data as a simple string argument rather than part of a potentially interpreted format string.
Specifically, in server.js at line 986 (and line 1002, which repeats the same pattern), the log statements of the form console.log(`Failed to get Wikipedia names for ${nameResult.scientificName}:`, error.message); and console.log(`Error fetching Wikipedia names for ${nameResult.scientificName}:`, error.message); should be changed to use a format string like "Failed to get Wikipedia names for %s: %s" and pass the relevant variables as arguments. Only these lines need modification.
No additional imports or library methods are necessary, as this is about changing format string usage.
| @@ -983,7 +983,7 @@ | ||
| } | ||
| }) | ||
| .catch((error) => { | ||
| console.log(`Failed to get Wikipedia names for ${nameResult.scientificName}:`, error.message); | ||
| console.log("Failed to get Wikipedia names for %s: %s", nameResult.scientificName, error.message); | ||
| return null; | ||
| }); | ||
|
|
||
| @@ -999,7 +999,7 @@ | ||
| } | ||
| } | ||
| } catch (error) { | ||
| console.log(`Error fetching Wikipedia names for ${nameResult.scientificName}:`, error.message); | ||
| console.log("Error fetching Wikipedia names for %s: %s", nameResult.scientificName, error.message); | ||
| } | ||
| } | ||
|
|
| } | ||
| } | ||
| } catch (error) { | ||
| console.log(`Error fetching Wikipedia names for ${nameResult.scientificName}:`, error.message); |
Check failure
Code scanning / CodeQL
Use of externally-controlled format string High
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 8 months ago
To fix this issue, we must ensure that user-controlled data (nameResult.scientificName) is never used directly as part of a format string in the first argument of console.log when additional arguments are supplied.
Instead, use the %s specifier in the literal format string and pass the untrusted data as a separate argument.
In server.js, at line 1002, replace:
console.log(`Error fetching Wikipedia names for ${nameResult.scientificName}:`, error.message);with:
console.log('Error fetching Wikipedia names for %s:', nameResult.scientificName, error.message);No additional imports or new methods are needed; simply modify how the console.log call is structured.
| @@ -999,7 +999,7 @@ | ||
| } | ||
| } | ||
| } catch (error) { | ||
| console.log(`Error fetching Wikipedia names for ${nameResult.scientificName}:`, error.message); | ||
| console.log('Error fetching Wikipedia names for %s:', nameResult.scientificName, error.message); | ||
| } | ||
| } | ||
|
|
| } | ||
| }) | ||
| .catch((error) => { | ||
| console.log(`Failed to get iNaturalist ${lang} name for ${nameResult.scientificName}:`, error.message); |
Check failure
Code scanning / CodeQL
Use of externally-controlled format string High
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 8 months ago
To address the externally-controlled format string issue, change any logging statements that interpolate untrusted data (here, nameResult.scientificName, which may be derived from req.originalUrl) directly into the log message using a template string. Instead, use a format specifier, such as %s, in the message string and pass the untrusted value as a second argument to console.log. This ensures that any format specifiers appearing in user-provided data are printed literally and do not affect logging behaviour. Make the same adjustment in all similar logging statements involving user input within the given file and regions (here, lines 1021 and 1037).
No new imports or methods are required.
| @@ -1018,7 +1018,7 @@ | ||
| } | ||
| }) | ||
| .catch((error) => { | ||
| console.log(`Failed to get iNaturalist ${lang} name for ${nameResult.scientificName}:`, error.message); | ||
| console.log('Failed to get iNaturalist %s name for %s:', lang, nameResult.scientificName, error.message); | ||
| return null; | ||
| }); | ||
|
|
||
| @@ -1034,7 +1034,7 @@ | ||
| } | ||
| } | ||
| } catch (error) { | ||
| console.log(`Error fetching iNaturalist ${lang} name for ${nameResult.scientificName}:`, error.message); | ||
| console.log('Error fetching iNaturalist %s name for %s:', lang, nameResult.scientificName, error.message); | ||
| } | ||
| } | ||
| } |
| } | ||
| } | ||
| } catch (error) { | ||
| console.log(`Error fetching iNaturalist ${lang} name for ${nameResult.scientificName}:`, error.message); |
Check failure
Code scanning / CodeQL
Use of externally-controlled format string High
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 8 months ago
To fix this issue, ensure that untrusted values (such as nameResult.scientificName, which ultimately come from user input) are never directly interpolated into format strings used as the first argument of console.log or similar functions, especially when additional arguments are passed. The cleanest solution is to use a format string with the %s substitution specifier and provide all arguments separately, so that any untrusted input will be safely rendered as a string rather than interpreted for additional formatting or placeholder replacement.
Edit line 1037 in server.js so that the message passed to console.log uses a fixed format string such as Error fetching iNaturalist %s name for %s: %s, and provides lang, nameResult.scientificName, and error.message as separate arguments.
No additional libraries or major code structure changes are required—just a single code line change.
| @@ -1034,7 +1034,7 @@ | ||
| } | ||
| } | ||
| } catch (error) { | ||
| console.log(`Error fetching iNaturalist ${lang} name for ${nameResult.scientificName}:`, error.message); | ||
| console.log('Error fetching iNaturalist %s name for %s: %s', lang, nameResult.scientificName, error.message); | ||
| } | ||
| } | ||
| } |
| headers: { | ||
| 'Authorization': req.headers['authorization'] | ||
| }, | ||
| timeout: 10000 | ||
| } | ||
| ); | ||
| return res.status(200).json(testResponse.data); | ||
| } catch (error) { | ||
| writeErrorLog(`Failed to fetch image from test server`, error); |
Check failure
Code scanning / CodeQL
Server-side request forgery Critical
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 8 months ago
To address the SSRF risk, user input used in the building of remote request URLs must be strictly validated. For this code, we need to ensure that id and password are well-formed and do not contain dangerous characters (e.g., /, \, ?, #, or ..). The best approach is to whitelist allowed values or at minimum reject possible traversal or injection attempts.
Since only a single code snippet is shown, add logic before using id and password to: (1) Validate id as a simple string (letters, digits, dashes/underscores only). (2) Validate password similarly (assuming it isn't meant to be arbitrary). If validation fails, return an error response and do not make the remote request.
Place this validation right after the assignment of id and password, before use in the remote request.
| @@ -2098,6 +2098,13 @@ | ||
| const password = urlParam.split("&")[1].toString(); | ||
| const id = urlParam.split("&")[0]; | ||
|
|
||
| // SSRF protection: validate id and password | ||
| const validId = /^[a-zA-Z0-9_\-]+$/.test(id); | ||
| const validPassword = typeof password === 'string' && password.length < 256 && !password.includes('&'); | ||
| if (!validId || !validPassword) { | ||
| return res.status(400).json({ error: "Invalid parameters." }); | ||
| } | ||
|
|
||
| fs.readdir(`${uploadsdir}/`, async (err, files) => { | ||
| let image_list = []; | ||
|
|
No description provided.