Problem/Motivation

After upgrading Drupal Core from 11.4.4 to 11.4.5, anonymous users submitting a Webform with a file upload field experience an issue where the uploaded file is lost during form submission
The upload initially succeeds and a temporary file entity is created. During form validation, the file field contains the expected file ID (fid). However, by the time the form submit handler and hook_webform_submission_presave() execute, the file field value becomes empty. As a result:
• The Webform submission does not store the uploaded file.
• Email handlers do not receive the file attachment.
• The temporary file remains in the system but is not associated with the submission.
• The issue occurs only for anonymous users.
• Authenticated users are not affected.

Steps to reproduce

  • Create a webform with file field, with file settings as private files(s3fs)
  • Submit a webform with file upload field as anonymous user.
  • Form submits successfully but file is removed from submission data.
  • If file field is mandatory then form gives error "file field is mandatory".

Proposed resolution

Remaining tasks

User interface changes

Introduced terminology

API changes

Data model changes

Release notes snippet

Comments

priyankampatil created an issue. See original summary.

cilefen’s picture

This could be related to #3593472: Insecure Direct Object Reference in Private File Uploads. Does reversing its changes to core/modules/file/src/Element/ManagedFile.php fix this?

cilefen’s picture

Status: Active » Postponed (maintainer needs more info)
Issue tags: +Needs steps to reproduce

I took 10 minutes to replicate the situation described in the issue summary (a form with a required file field submitted by an anonymous user), but I couldn't reproduce the bug. We need additional steps to reproduce.

priyankampatil’s picture

@cilefen File field uses private storage which is s3fs

cilefen’s picture

Title: After upgrading Drupal Core from 11.4.4 to 11.4.5, anonymous users submitting a Webform with a file upload field experience an issue where the uploaded file is lost during form submission » After upgrading Drupal Core from 11.4.4 to 11.4.5, anonymous users submitting a Webform with a file upload field experience an issue where the uploaded file is lost during form submission, when private storage is S3
Issue tags: +Needs issue summary update

Would you answer my question in comment #2 and update the issue summary with steps to reproduce? A complete understanding of the bug is necessary to proceed.

priyankampatil’s picture

Issue summary: View changes

@cilefen It is related to #3593472: Insecure Direct Object Reference in Private File Uploads. Reversing its changes to core/modules/file/src/Element/ManagedFile.php fix this issue.

cilefen’s picture

Status: Postponed (maintainer needs more info) » Active
Issue tags: -Needs steps to reproduce, -Needs issue summary update

This may be more of an S3 module issue to fix, or technically a Core regression, but I am reactivating this issue to increase visibility.

cilefen’s picture

Status: Active » Postponed (maintainer needs more info)

Actually, someone needs to test the bug with a Drupal Core file field to determine if this is a Webform issue at all. @priyankampatil, would you please do that test?

quietone’s picture

Title: After upgrading Drupal Core from 11.4.4 to 11.4.5, anonymous users submitting a Webform with a file upload field experience an issue where the uploaded file is lost during form submission, when private storage is S3 » Upgrade to 11.4.5, a Webform with a file upload field loses file on submit for anonymous
Assigned: priyankampatil » Unassigned

Updating the title per Title guidelines. And un-assigning per Assigning ownership of a Drupal core issue.

aporie’s picture

Hi cilefen,

I can't test it right now, but I can tell you how this issue happened to me. Maybe it'll help.

I'm using managed_file on a custom form (so drupal core related and not webform related).

As anonymous users, because my file managed is set to private:

$form['something'] = [
      '#type' => 'managed_file',
      '#title' => $this->t('Upload files'),
      '#upload_location' => 'private:/somewhere/',
      '#required' => TRUE,
      '#multiple' => TRUE,
    ];

Then the bug appears. It's not related to webform IMO. It's more a drupal core issue related to #3593472: Insecure Direct Object Reference in Private File Uploads.

The issue is that since #3593472 every files get rejected if they are private (anonymous users don't have access to it), so there is no way for anonymous to upload private files anymore.

cilefen’s picture

Project: Drupal core » Webform
Version: 11.4.x-dev » 6.3.x-dev
Component: file system » Code
Priority: Normal » Major
Status: Postponed (maintainer needs more info) » Active

Good, that is what I guessed in the first comment.

priyankampatil’s picture

Hi Cilefen,

Previously, we were able to resolve the anonymous file upload issue in Drupal 11.4.6 by reverting the changes associated with Drupal core issue #3593472.

After upgrading to Drupal 11.4.7 and applying the latest Webform security update, the issue has resurfaced. Reverting the Drupal core change alone no longer resolves it because Webform has introduced similar file validation restrictions in its security update. As a result, Webform submissions containing a file upload field fail for anonymous users with the error:

“The uploaded file is invalid.”

bkosborne’s picture

Project: Webform » Drupal core
Version: 6.3.x-dev » main
Component: Code » file.module

Fixing project metadata, issue #11 misread the previous comment

aporie’s picture

This is a hard issue to tackle because we need to give an open door to potential file spoofers.

It all depends on the level of security websites need.

The initial security issue is public so, bots could use it to scan recently posted sensitive files.

There is no real perfect solution here, apart from asking your users to create an account before they upload sensitive files ....

I think each websites should take care of their own security level. As for the Drupal project, a 24h window looks good to me.

We set temporary files to be visible to Anonymous, and configure the Cron to delete them after 24h (or 1h, I don't know). It won't prevent bots from fetching all these data.

It's for each institutions to configure this according to the sensitivity of their data.

Or we do it reverse. The ones who don't need so much protection patches core? But then, anonymous private files don't work out of the box ...

[Edit] or we make files non predictable IDs ... We make a random hash for each files. That would work.

edyuenyw’s picture

My site is a headless. And after some debugging, I noticed file attachment failed for multipage form.
Front end now managed to retain the session/cookie for anonymous user and eventually able to get data back from $session->get('anonymous_allowed_file_ids'

My issue is fixed for now:
1. Webform page 1 with upload document field upload $session->set('anonymous_allowed_file_ids', $allowed_temp_files)
2. Click "Next" page and session is retained and able to get the temp files.

I am still working with my team to see if there are any security implications.
Putting out here to see if there are other solutions. I am interested to get opinions on this.

cmlara’s picture

Something like the file upload returning a nonce that has to be attached with the file FID could be a solution. Provide one time authentication of the attachments so that even if you know the ID unless you have permissions you’re unable to add it as a new attachment to the issue.

bkosborne’s picture

I'm trying to reproduce this with Webform and cannot. Can this only be reproduced with the s3fs module serving as the private file system?

My set up is:

Drupal 11.4.11
Webform 6.3.1

I tried these three webform setups:

  1. Text element and a non-required file element using private FS. Anonymous user was able to submit the file successfully.
  2. Text element and a required file element using private FS. Anonymous user was able to submit the file successfully.
  3. Multi-page webform, with text element on one page and required file element on the other. Anonymous user was able to submit the file successfully.

The original reporter indicate they were using s3fs. But aporie in #10 didn't mention anything about s3fs, though they are using a custom form element and not webform. What private filesystem are you using aporie?

Drupal 11.4.5 (which included the security hardening in #3593472: Insecure Direct Object Reference in Private File Uploads) has been out for 2.5 months, and there's been two core security releases since then, so I have to imagine that there's a lot of people using versions of Drupal with the modified managed file behavior. I would have expected to see a lot more people reporting this issue, which makes me think that there's some uncommon setup involved here.

aporie’s picture

Hi @bloksborne,

I was starting to get my setup ready to do tests on my side when I figured out probably what is the problem and why you can't reproduce it.

By default, setting files to be private does not remove access to these files to (anyone) anonymous user. What people complaining about this bug probably have, is some kind of restrictions on their file accesses. For example in my case:

/**
 * Implements hook_file_access().
 */
function my_module_file_access(FileInterface $file, $operation, AccountProxyInterface $account) {
  // Give access to moderator and administrator.
  if (in_array('moderator', $account->getRoles()) || in_array('administrator', $account->getRoles())) {
    return AccessResult::allowed();
  }
  // Any other user.
  if ($operation == 'download') {
    $uri = $file->get('uri')->first()->getValue()['value'];
    // Public access, let FileAccessControlHandler deal with it.
    if (strpos($uri, 'public://') !== FALSE) {
      return AccessResult::allowed();
    }
    // important documents access.
    if (strpos($uri, 'private://important_documents') !== FALSE) {
      if ($file->getOwnerId() == $account->id()) {
        return AccessResult::allowed();
      }
    }
    // ...
  }
  // For all other cases, we deny access.
  // Here anonymous do not have access to their file because they do not own it.
  // Since drupal stopped tracking anonymous users, $file->getOwnerId() == $account->id()
  // will never return true.
  return AccessResult::forbidden();
}

Then we have the issue at two points actually (and not just one like the patch I made):

In web/core/modules/file/src/Element/ManagedFile.php::80 and web/core/modules/file/src/Element/ManagedFile.php::108:

 if (!$file->access('download')) {
   $force_default = TRUE;
   break;
}

Anonymous are denied access, the bug is reproducible. But again. It's not webform :D

[EDIT] There is actually an already implemented solution that we can reuse in ManagedFile. I'll take a deeper look when I have time:

// Since file ownership can't be determined for anonymous users,
// they are not allowed to reuse temporary files at all. But
// they do need to be able to reuse their own files from earlier
// submissions of the same form, so to allow that, check for the
// token added by $this->processManagedFile().
if (\Drupal::currentUser()->isAnonymous()) {
  $parents = array_merge($element['#parents'], ['file_' . $file->id(), 'fid_token']);
  $token = NestedArray::getValue($form_state->getUserInput(), $parents);
  $file_hmac = Crypt::hmacBase64('file-' . $file->id(), \Drupal::service('private_key')->get() . Settings::getHashSalt());
  if ($token === NULL || !hash_equals($file_hmac, $token)) {
    $force_default = TRUE;
    break;
  }
}
aporie’s picture

Title: Upgrade to 11.4.5, a Webform with a file upload field loses file on submit for anonymous » Upgrade to 11.4.5, own private restricted files are not accessible to anonymous
aporie’s picture

So, I did more tests today and actually, in my case the bug is not in core, it's on my website.

Testing on a fresh install I came to the the same conclusion as you @bkosborne, maybe you actually did tested with a specific access.

In my case, I actually missed my specific path were the bug occured (only moderator and administrator are supposed to see these files, even though giving access to the owner makes sense, it's just they never see them anywhere anyway):

if (strpos($uri, 'private://important_documents') !== FALSE) {
      if ($file->getOwnerId() == $account->id()) {
        return AccessResult::allowed();
      }
    }

Even as an anonymous this condition ends up being $file->getOwnerId() === 0 and $account->id() === 0, so the anonymous has AccessResult::allowed() and there is no bug.

I fixed my application on my side, seems logic that if I didn't give access to the owner of the file, they couldn't see it ^^.

I don't know if the reporter or any other users encountering this bug have another root cause to it.

cmlara’s picture

Even as an anonymous this condition ends up being $file->getOwnerId() === 0 and $account->id() === 0, so the anonymous has AccessResult::allowed() and there is no bug.

If this is an entity access or file download hook you would now be allowing any anonymous user access to (including download) any other anonymous users files in private://important_documents.

Generally that is not desired for most using private:// storage as it essentially becomes equivalent to public:// (just more system resource intensive to serve).

aporie’s picture

Yes, that was my night thoughts. We're still not fully around this issue.

It feels like I just re-opened the exact same security issue, the fix from the upgrade to 11.4.5 was attempting to fix.

TBC