Skip to content

Commit c17728f

Browse files
committed
Don’t allow pointing a Local volume to a system directory
1 parent 3f36fbe commit c17728f

File tree

2 files changed

+56
-0
lines changed

2 files changed

+56
-0
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
- Adjusted GraphQL complexity values for relational fields.
1111
- Updated Composer to 2.0.9.
1212

13+
### Security
14+
- It’s no longer possible to save a Local volume with the File System Path setting set to a system directory (e.g. the `templates/` or `vendor/` folders).
15+
1316
## 3.6.6 - 2021-02-15
1417

1518
### Added

src/volumes/Local.php

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use League\Flysystem\Adapter\Local as LocalAdapter;
1313
use League\Flysystem\FileExistsException;
1414
use League\Flysystem\FileNotFoundException;
15+
use yii\validators\InlineValidator;
1516

1617
/**
1718
* The local volume class. Handles the implementation of the local filesystem as a volume in
@@ -58,9 +59,61 @@ protected function defineRules(): array
5859
{
5960
$rules = parent::defineRules();
6061
$rules[] = [['path'], 'required'];
62+
$rules[] = [['path'], 'validatePath'];
6163
return $rules;
6264
}
6365

66+
/**
67+
* @param string $attribute
68+
* @param array|null $params
69+
* @param InlineValidator $validator
70+
* @param string $path
71+
* @return void
72+
* @since 3.6.7
73+
*/
74+
public function validatePath(string $attribute, ?array $params, InlineValidator $validator, string $path): void
75+
{
76+
if ($created = !file_exists($path)) {
77+
FileHelper::createDirectory($path);
78+
}
79+
80+
$path = realpath($this->getRootPath());
81+
82+
if ($path === false) {
83+
return;
84+
}
85+
86+
// Make sure it’s not within any of the system directories
87+
$pathService = Craft::$app->getPath();
88+
$systemDirs = [
89+
Craft::getAlias('@contentMigrations'),
90+
Craft::getAlias('@lib'),
91+
$pathService->getComposerBackupsPath(false),
92+
$pathService->getConfigBackupPath(false),
93+
$pathService->getConfigDeltaPath(false),
94+
$pathService->getConfigPath(),
95+
$pathService->getDbBackupPath(false),
96+
$pathService->getLogPath(false),
97+
$pathService->getRebrandPath(false),
98+
$pathService->getRuntimePath(false),
99+
$pathService->getSiteTemplatesPath(),
100+
$pathService->getSiteTranslationsPath(),
101+
$pathService->getTestsPath(),
102+
$pathService->getVendorPath(),
103+
];
104+
105+
foreach ($systemDirs as $dir) {
106+
$dir = realpath($dir);
107+
if ($dir !== false && strpos($path . DIRECTORY_SEPARATOR, $dir . DIRECTORY_SEPARATOR) === 0) {
108+
$validator->addError($this, $attribute, Craft::t('app', 'Local volumes cannot be located within system directories.'));
109+
if ($created) {
110+
FileHelper::removeDirectory($path);
111+
}
112+
break;
113+
}
114+
}
115+
}
116+
64117
/**
65118
* @inheritdoc
66119
*/

0 commit comments

Comments
 (0)