Skip to content

Fix path traversal in save_account_details (SonarQube jssecurity:S2083)#62

Open
devin-ai-integration[bot] wants to merge 1 commit into
mainfrom
devin/sonarqube-fix-AZoM-zIBs8nSf3VywcRW-1782983122
Open

Fix path traversal in save_account_details (SonarQube jssecurity:S2083)#62
devin-ai-integration[bot] wants to merge 1 commit into
mainfrom
devin/sonarqube-fix-AZoM-zIBs8nSf3VywcRW-1782983122

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Jul 2, 2026

Copy link
Copy Markdown

Summary

Remediates SonarQube BLOCKER issue AZoM-zIBs8nSf3VywcRW (rule jssecurity:S2083, Path Traversal) at routes/index.js:107.

save_account_details passed the raw request body straight into the view engine:

const profile = req.body            // fully attacker-controlled
// ...validation of email/phone/name/country...
return res.render('account.hbs', profile)

The hbs engine (registered in app.js) treats certain locals — notably layout — as template file paths. Because profile is the untrusted req.body, an attacker could add a layout property whose value escapes the views directory (e.g. ../../etc/...), turning render locals into a user-controlled filesystem path.

Fix

Pass an allowlist of only the expected, validated fields instead of the whole body, so no attacker-supplied property can reach the engine's path resolution:

const safeProfile = {
  firstname: validator.rtrim(profile.firstname),
  lastname: validator.rtrim(profile.lastname),
  email: profile.email,
  phone: profile.phone,
  country: profile.country
}
return res.render('account.hbs', safeProfile)

views/account.hbs only references firstname, lastname, email, phone, country, so rendering behavior is unchanged.

Scope is limited to this single sink; no unrelated code was touched. node --check routes/index.js passes. (npm test runs snyk test, which needs Snyk auth, so it was skipped per task guidance.)

Link to Devin session: https://app.devin.ai/sessions/e88cfeb34e794efb9f7e973443203788
Requested by: @joao-cognition


Devin Review

Status Commit
⚪ Not started

Run Devin Review

Open in Devin Review (Staging)

Pass an allowlisted set of locals to res.render instead of the raw
request body, preventing a user-controlled 'layout' property from being
resolved to a filesystem path by the hbs engine.

Co-Authored-By: Joao Esteves <joao.esteves@cognition.ai>
@devin-ai-integration

Copy link
Copy Markdown
Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

Comment thread routes/index.js
const safeProfile = {
firstname: validator.rtrim(profile.firstname),
lastname: validator.rtrim(profile.lastname),
email: profile.email,
@devin-ai-integration

Copy link
Copy Markdown
Author

SonarQube remediation: AZoM-zIBs8nSf3VywcRW (rule jssecurity:S2083)

Vulnerability: Path Traversal (BLOCKER) at routes/index.js:107, message "Change this code to not construct the path from user-controlled data."

Root cause: save_account_details assigned profile = req.body (fully attacker-controlled) and then called res.render('account.hbs', profile). The hbs view engine (registered in app.js as app.engine('hbs', hbs.__express)) interprets certain render locals — notably layout — as template file paths. Since the untrusted body was passed verbatim as locals, an attacker could inject a layout (or similar) property whose value escapes the views directory, causing a filesystem path to be built from user-controlled data.

Fix (what changed and why): Instead of forwarding the raw request body, the render now receives an explicit allowlist of only the expected, already-validated fields:

const safeProfile = {
  firstname: validator.rtrim(profile.firstname),
  lastname: validator.rtrim(profile.lastname),
  email: profile.email,
  phone: profile.phone,
  country: profile.country
}
return res.render('account.hbs', safeProfile)

This prevents any attacker-supplied property (e.g. layout) from reaching the template engine's path resolution, remediating the path traversal. views/account.hbs only references firstname, lastname, email, phone, and country, so rendering output is unchanged. The change is scoped to this single sink; no unrelated code was modified.

The SonarQube issue was intentionally not marked resolved/false-positive — leaving it for SonarQube to re-scan and clear.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant