Skip to content
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

feat(fs): add safeguard to ensure all paths are within expected directory #16125

Closed
wants to merge 9 commits into from

Conversation

Churro
Copy link
Collaborator

@Churro Churro commented Jun 17, 2022

Changes

A preemptive check to ensure that potentially insecure relative or absolute paths are strictly contained within an expected folder. This is a safeguard to prevent potential path traversal attacks that may occur in case paths from processed repositories are used in file system operations.

node provides a guideline to prevent directory traversal. With an arbitrary path in fileName, the check could be simply:

const { localDir } = GlobalConfig.get();
const localDirName = upath.join(localDir, fileName);
if (localDir && !localFileName.startsWith(localDir)) {
  logger.warn('Preventing access to file outside the base directory');
  return null;
}
  • upath.join() concats the two parameters and normalizes the result (see here).
    This means that upath.join('/tmp/renovate', '../../etc/passwd') becomes /etc/passwd

The only issue with path.join() is that this breaks when file system logic like . or ./ is used. E.g., with localDir = '.' and fileName = 'asdf', the join result is simply asdf and the startsWith check would fail. This would be the case with the tests in https://github.com/renovatebot/renovate/blob/main/lib/modules/manager/npm/post-update/yarn.spec.ts
(Note: Changing these tests to use '' instead of '.' would essentially be an alternative to changing all join ops to resolve)

The alternative used in this PR is path.resolve(), which basically enforces that all paths are relative to localDir. Good examples on the differences between join and resolve can also be found here.

Test repository: https://github.com/Churro/renovate-applyfrom-traversal/blob/master/dummy/build.gradle
-> only works so far when the commit in this PR is applied on #16030

Output:

WARN: Preventing access to file outside the base directory (repository=Churro/renovate-applyfrom-traversal)
WARN: Failed to process Gradle file (repository=Churro/renovate-applyfrom-traversal)
       "scriptFilePath": "../somefile.gradle"
WARN: Failed to process Gradle file (repository=Churro/renovate-applyfrom-traversal)
       "scriptFilePath": "somefile_other_file.gradle"
WARN: Failed to process Gradle file (repository=Churro/renovate-applyfrom-traversal)
       "scriptFilePath": "dummy/etc/somefile_other_other_file.gradle"

What can be noticed is that wandering around directories using ../ still works unless you leave the base dir. Other absolute paths are rewritten by path.resolve() to be relative to base dir.

Context

Related to #16030 (comment)

Documentation (please check one with an [x])

  • I have updated the documentation, or
  • No documentation update is required

How I've tested my work (please tick one)

I have verified these changes via:

  • Code inspection only, or
  • Newly added/modified unit tests, or
  • No unit tests but ran on a real repository, or
  • Both unit tests + ran on a real repository

Copy link
Collaborator

@rarkins rarkins left a comment

Choose a reason for hiding this comment

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

Should we warn for each of these? Ie they aren't expect yo occur so are either something malicious or will be surfacing bugs we would have otherwise missed?

lib/util/fs/index.ts Outdated Show resolved Hide resolved
@Churro
Copy link
Collaborator Author

Churro commented Jun 17, 2022

Should we warn for each of these? Ie they aren't expect yo occur so are either something malicious or will be surfacing bugs we would have otherwise missed?

If unusual or malicious, it may useful to see that in logs too. I guess that more covert bugs or edge cases with artifact updates may simply go unnoticed otherwise.

lib/util/fs/index.ts Outdated Show resolved Hide resolved
Churro and others added 2 commits June 17, 2022 15:10
Co-authored-by: Rhys Arkins <rhys@arkins.net>
@rarkins rarkins requested a review from viceice June 17, 2022 19:42
lib/util/fs/index.ts Outdated Show resolved Hide resolved
@viceice
Copy link
Member

viceice commented Jun 17, 2022

we also should make those properties mandatory, as they never should be null or undefined at runtime.

@Churro
Copy link
Collaborator Author

Churro commented Jun 18, 2022

we also should make those properties mandatory, as they never should be null or undefined at runtime.

Probably in another PR? That change would affect > 20 tests and it's not really related to this safeguard but more of a general thing...

@zharinov zharinov self-requested a review June 18, 2022 16:33
zharinov
zharinov previously approved these changes Jun 18, 2022
Copy link
Collaborator

@zharinov zharinov left a comment

Choose a reason for hiding this comment

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

I like the concept of file traversal guarding is introduced in the code now, and further improvements can be made in separate PRs. This one looks good to me.

@Churro
Copy link
Collaborator Author

Churro commented Jun 25, 2022

@viceice, do you agree with @zharinov that this PR is fine for now and that improvements to properties can still be made separately? IMO the safeguard itself already adds noteworthy value

Copy link
Member

@viceice viceice left a comment

Choose a reason for hiding this comment

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

i do not agree @zharinov we should make this as safe as possible now. I'm pretty sure it will be forgotten to do.

lib/util/fs/index.spec.ts Show resolved Hide resolved
lib/util/fs/index.ts Outdated Show resolved Hide resolved
@zharinov
Copy link
Collaborator

i do not agree @zharinov we should make this as safe as possible now. I'm pretty sure it will be forgotten to do.

My point was to wait for this PR to be merged, so I'll be able to apply these safeguards to the functions of proxies.ts as well. I have a draft issue to do this on my personal GitHub project.

@viceice
Copy link
Member

viceice commented Jun 25, 2022

i do not agree @zharinov we should make this as safe as possible now. I'm pretty sure it will be forgotten to do.

My point was to wait for this PR to be merged, so I'll be able to apply these safeguards to the functions of proxies.ts as well. I have a draft issue to do this on my personal GitHub project.

ok, sounds good 👍

@Churro Churro dismissed stale reviews from ghost and zharinov via f861c55 June 25, 2022 20:00
@Churro Churro requested a review from viceice June 25, 2022 21:31
Comment on lines +14 to +23
function isPathInBaseDir(path: string, baseDir: string): boolean {
if (!path.startsWith(upath.resolve(baseDir))) {
logger.warn(
{ path, baseDir },
'Preventing access to file outside the base directory'
);
return false;
}

return true;
Copy link
Member

Choose a reason for hiding this comment

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

@rarkins @zharinov we should probably throw an error here and abort further processing.

so function shou be rename to validatePathInBaseDir or something like that and return never?

Copy link
Collaborator

Choose a reason for hiding this comment

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

"abort further processing" = stop running on the repo?

Copy link
Member

Choose a reason for hiding this comment

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

yes

Copy link
Collaborator

Choose a reason for hiding this comment

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

Sounds reasonable + further we need to ensure we don't use fs and fs-extra directly (i.e. migrate and add lint rule)

@zharinov
Copy link
Collaborator

@Churro Thank you for your help. If you don't mind, I'll continue to work on it on my own

Superseded by #16313

@zharinov zharinov closed this Jun 28, 2022
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jul 29, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants