5 * Contains \Drupal\security_review\Checks\UploadExtensions.
8 namespace Drupal\security_review\Checks;
10 use Drupal\Core\Entity\Entity;
12 use Drupal\field\Entity\FieldConfig;
13 use Drupal\security_review\Check;
14 use Drupal\security_review\CheckResult;
15 use Symfony\Component\Routing\Exception\RouteNotFoundException;
18 * Checks for unsafe extensions in the allowed extensions settings of fields.
20 class UploadExtensions extends Check {
25 public function getNamespace() {
26 return 'Security Review';
32 public function getTitle() {
33 return 'Allowed upload extensions';
39 public function getMachineTitle() {
40 return 'upload_extensions';
46 public function run() {
47 // If field is not enabled return with INFO.
48 if (!$this->moduleHandler()->moduleExists('field')) {
49 return $this->createResult(CheckResult::INFO);
52 $result = CheckResult::SUCCESS;
55 // Check field configuration entities.
56 foreach (FieldConfig::loadMultiple() as $entity) {
57 /** @var FieldConfig $entity */
58 $extensions = $entity->getSetting('file_extensions');
59 if ($extensions != NULL) {
60 $extensions = explode(' ', $extensions);
61 $intersect = array_intersect($extensions, $this->security()->unsafeExtensions());
62 // $intersect holds the unsafe extensions this entity allows.
63 foreach ($intersect as $unsafe_extension) {
64 $findings[$entity->id()][] = $unsafe_extension;
69 if (!empty($findings)) {
70 $result = CheckResult::FAIL;
73 return $this->createResult($result, $findings);
79 public function help() {
81 $paragraphs[] = $this->t(
82 'File and image fields allow for uploaded files. Some extensions are considered dangerous because the files can be evaluated and then executed in the browser. A malicious user could use this opening to gain control of your site. Review <a href=":url">all fields on your site</a>.',
83 [':url' => Url::fromRoute('entity.field_storage_config.collection')->toString()]
87 '#theme' => 'check_help',
88 '#title' => 'Allowed upload extensions',
89 '#paragraphs' => $paragraphs,
96 public function evaluate(CheckResult $result) {
97 $findings = $result->findings();
98 if (empty($findings)) {
103 $paragraphs[] = $this->t('The following extensions are considered unsafe and should be removed or limited from use. Or, be sure you are not granting untrusted users the ability to upload files.');
106 foreach ($findings as $entity_id => $unsafe_extensions) {
107 $entity = FieldConfig::load($entity_id);
108 /** @var FieldConfig $entity */
110 foreach ($unsafe_extensions as $extension) {
112 'Review @type in <em>@field</em> field on @bundle',
114 '@type' => $extension,
115 '@field' => $entity->label(),
116 '@bundle' => $entity->getTargetBundle(),
120 // Try to get an edit url.
122 $url_params = ['field_config' => $entity->id()];
123 if ($entity->getTargetEntityTypeId() == 'node') {
124 $url_params['node_type'] = $entity->getTargetBundle();
126 $url = Url::fromRoute(
127 'entity.field_config.' . $entity->getTargetEntityTypeId() . '_field_edit_form',
130 $items[] = $this->l($item, $url);
132 catch (RouteNotFoundException $e) {
139 '#theme' => 'check_evaluation',
140 '#paragraphs' => $paragraphs,
148 public function evaluatePlain(CheckResult $result) {
149 $findings = $result->findings();
150 if (empty($findings)) {
155 foreach ($findings as $entity_id => $unsafe_extensions) {
156 $entity = FieldConfig::load($entity_id);
157 /** @var FieldConfig $entity */
160 '@bundle: field @field',
162 '@bundle' => $entity->getTargetBundle(),
163 '@field' => $entity->label(),
166 $output .= "\n\t" . implode(', ', $unsafe_extensions) . "\n";
175 public function getMessage($result_const) {
176 switch ($result_const) {
177 case CheckResult::SUCCESS:
178 return $this->t('Only safe extensions are allowed for uploaded files and images.');
180 case CheckResult::FAIL:
181 return $this->t('Unsafe file extensions are allowed in uploads.');
183 case CheckResult::INFO:
184 return $this->t('Module field is not enabled.');
187 return $this->t('Unexpected result.');