Skip to content

Fix Uncontrolled data used in path expression #3821

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

odaysec
Copy link

@odaysec odaysec commented May 14, 2025

Pull Request Type

const filePath = path.resolve(documentsPath, normalizePath(filename));
if (
!fs.existsSync(filePath) ||
!isWithin(documentsPath, filePath) ||
!fs.lstatSync(filePath).isFile()
)
return;
console.log(`Purging source document of ${filename}.`);
fs.rmSync(filePath);

fix the issue need to ensure that the filename input is properly sanitized and validated before constructing the file path. Specifically:

  1. Use the path.resolve function to normalize the path and remove any .. segments.
  2. Verify that the resolved path starts with the documentsPath to ensure it is confined to the intended directory.
  3. Throw an error or return early if the validation fails.

The normalizePath function should also be updated to provide stricter sanitization, ensuring that the resulting path is safe to use.


  • ✨ feat
  • 🐛 fix
  • ♻️ refactor
  • 💄 style
  • 🔨 chore
  • 📝 docs

Developer Validations

  • I ran yarn lint from the root of the repo & committed changes
  • Relevant documentation has been updated
  • I have tested my code functionality
  • Docker build succeeds locally

Copy link
Member

@timothycarambat timothycarambat left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking for feedback on comments

Comment on lines +260 to 266
.replace(/^(\.\.(\/|\\|$))+/, "") // Remove leading `../` sequences
.replace(/(\.\.(\/|\\|$))+/g, "") // Remove any remaining `../` segments
.trim();
if (["..", ".", "/"].includes(result)) throw new Error("Invalid path.");
if (!result || result.startsWith("/") || result.includes("..")) {
throw new Error("Invalid or unsafe path.");
}
return result;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good improvement to apply 👍

Comment on lines +180 to +196
try {
const sanitizedFilename = normalizePath(filename);
const filePath = path.resolve(documentsPath, sanitizedFilename);

if (
!fs.existsSync(filePath) ||
!isWithin(documentsPath, filePath) ||
!fs.lstatSync(filePath).isFile()
)
return;
if (
!filePath.startsWith(documentsPath) || // Ensure the path is within documentsPath
!fs.existsSync(filePath) ||
!fs.lstatSync(filePath).isFile()
) {
throw new Error(`Invalid or unsafe file path: ${filename}`);
}

console.log(`Purging source document of ${filename}.`);
fs.rmSync(filePath);
console.log(`Purging source document of ${filename}.`);
fs.rmSync(filePath);
} catch (error) {
console.error(`Failed to purge source document: ${error.message}`);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const sanitizedFilename = normalizePath(filename);
const filePath = path.resolve(documentsPath, sanitizedFilename);

is the same as

const filePath = path.resolve(documentsPath, normalizePath(filename));

and this block

 !filePath.startsWith(documentsPath) || // Ensure the path is within documentsPath
!fs.existsSync(filePath) ||
 !fs.lstatSync(filePath).isFile()

filePath.startsWith(documentsPath) does a similar check of what isWithin does already, no? So functionally, the logic has not changed here. We could have both or check within before checking existence, maybe?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants