In SA-CONTRIB-2010-066 two different XSS vulnerabilities were closed related to the file names of uploaded files.
It's possible that one or both are present in Drupal 7 core due to the FileField being brought into core.
the patch for FileField:
Index: filefield.token.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/filefield/filefield.token.inc,v
retrieving revision 1.5
diff -u -p -r1.5 filefield.token.inc
--- filefield.token.inc 30 Jul 2009 16:47:43 -0000 1.5
+++ filefield.token.inc 16 Jun 2010 20:43:38 -0000
@@ -38,9 +38,9 @@ function filefield_token_values($type, $
if ($type == 'field' && isset($object[0]['fid'])) {
$item = $object[0];
$tokens['filefield-fid'] = $item['fid'];
- $tokens['filefield-description'] = isset($item['data']['description']) ? $item['data']['description'] : '';
- $tokens['filefield-filename'] = $item['filename'];
- $tokens['filefield-filepath'] = $item['filepath'];
+ $tokens['filefield-description'] = isset($item['data']['description']) ? check_plain($item['data']['description']) : '';
+ $tokens['filefield-filename'] = check_plain($item['filename']);
+ $tokens['filefield-filepath'] = check_plain($item['filepath']);
$tokens['filefield-filemime'] = $item['filemime'];
$tokens['filefield-filesize'] = $item['filesize'];
$tokens['filefield-filesize_formatted'] = format_size($item['filesize']);
Index: filefield_formatter.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/filefield/filefield_formatter.inc,v
retrieving revision 1.16
diff -u -p -r1.16 filefield_formatter.inc
--- filefield_formatter.inc 24 Apr 2010 03:54:59 -0000 1.16
+++ filefield_formatter.inc 16 Jun 2010 20:43:38 -0000
@@ -39,8 +39,7 @@ function theme_filefield_formatter_path_
if (empty($item['filepath']) && !empty($item['fid'])) {
$item = array_merge($item, field_file_load($item['fid']));
}
-
- return empty($item['filepath']) ? '' : file_create_path($item['filepath']);
+ return empty($item['filepath']) ? '' : check_plain(file_create_path($item['filepath']));
}
/**
@@ -63,7 +62,21 @@ function theme_filefield_formatter_url_p
$item = array_merge($item, field_file_load($item['fid']));
}
- return empty($item['filepath']) ? '' : file_create_url($item['filepath']);
+ if (empty($item['filepath'])) {
+ return '';
+ }
+
+ // Encode the parts of the path to ensure URLs operate within href attributes.
+ // Private file paths are urlencoded for us inside of file_create_url().
+ if (variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC) == FILE_DOWNLOADS_PUBLIC) {
+ $parts = explode('/', $item['filepath']);
+ foreach ($parts as $index => $part) {
+ $parts[$index] = rawurlencode($part);
+ }
+ $item['filepath'] = implode('/', $parts);
+ }
+
+ return file_create_url($item['filepath']);
}
Comments
Comment #1
rszrama commentedReading over the File token integration in system.tokens.inc shows the tokens have been sanitized where requested.
Regarding the second chunk, in function file_field_formatter_view() of file.field.inc in D7:
This seems related to the fix applied in SA-CONTRIB-2010-066, so I'm guessing file_create_url($item['uri']) needs to be wrapped in check_plain()?
I'm not actually sure what to make of the third chunk, as I don't see relevant code in the current File module.
Comment #2
int commentedadd beta blocker tag
Comment #3
philbar commentedThis module does not appear on the D7 beta blocker section of the community initiative page. Should it be?
Comment #4
rszrama commentedAdded it there.
Comment #5
pwolanin commentedAfter struggling with this issue for D6- the file path and file URL have to be treated quite differently. We have to insure the URL can be used in a web address, while the path is not guaranteed to be usable that way.
For this reason, we don't apply check_plain() to file_create_url(), but instead do the urlencode dance.
Comment #6
tstoecklerThis is a first stab at fixing file_field_formatter_view(). This is the first time I've ever been involved with stream wrappers / file API / file.module and in addition to the code being extremely ugly, I'm pretty certain the approach is also flawed. But now you experts have a patch to review and can tell me how to do it better/right. :)
Comment #7
tstoecklerComment #8
int commented"But now you experts have a patch to review.."
Comment #9
dhthwy commentedafter thorough testing, AFAICT Drupal 7 core is not affected, so no patch is necessary.
File field's hook implementation of hook_field_formatter_view() calls file_create_url() for the 'URL to file' format, the other formats ('generic file' and 'table of files') use hook theme_file_link() which calls file_create_url() and l(). l() also check_plain()s the file's description (link anchor text) when descriptions are used for the 'generic file' and 'table of files' formats (the 'URL to file' format is plain text and therefore doesn't use a description).
file_create_url() URL encodes public and private file schemes via the call to $wrapper->getExternalUrl():
In file_create_url():
For the public stream wrapper this invokes:
For the private stream wrapper this invokes:
pwolanin, penny for your thoughts?
Comment #10
dhthwy commentedComment #11
pwolanin commentedSo, looking at the token code, seems like file module doesn't provide any(!) tokens in Drupal 7 core, so we don't need to worry about that part (for core at least).
In http://api.drupal.org/api/function/file_create_url/7
it looks like there could be a vulnerability for relative URLs or http/https URLs.
Also, in terms of the token values, it seems like we might actually get double encoding in some cases
http://api.drupal.org/api/function/system_tokens/7
So far I agree with the comment above that this is likely not an issue in Drupal 7 core.
Comment #12
dhthwy commentedpwolanin, I think you're right about http/https/relative URLs, but whose responsibility is it to url encode those? It seems like it would be the callers.
Comment #13
damien tournoud commentedThis definitely needs a check_plain().
Comment #14
pwolanin commented@dhtwy - well I feel like we need to have a consistent expectation. If file_create_url encodes some URLs, then I think it should encode all of them?
Comment #15
pwolanin commentedI think calling url() inside system_tokens() is wrong.
Comment #16
dhthwy commentedpwolanin, yea, you're probably right.
Comment #17
damien tournoud commentedAll those url() in system_tokens() needs to be wrapped in check_plain(), or they are not safe to output in an HTML context.
Comment #18
pwolanin commentedshould probably be:
Comment #19
pwolanin commentedSo imagining we have a URL as the file URL. Do we require that to be URL encoded in the DB? I'm not sure you can do this anywhere in Drupal core, but we need to think about "interesting" contrib applications.
Comment #20
pwolanin commentedThis patch is a starting point, but wrong for file_create_url(). We don't actually want to use drupal_encode_path() on the full uri, since it may contain a query string.
E.g. imagine that the actual name of the file is passed to a CDN in the query string, or we are using something like s3 where we include an access token in the query string.
It seems like we need to build a new helper function to encode an arbitrary URL?
Comment #21
damien tournoud commentedThis is not a question of urlencoding, but of HTML encoding. Even a properly encoded URL needs to be HTML encoded before being output. system_token() is way too late in the process to worry about URL-encoding.
Comment #22
pwolanin commentedhopefully this is more along the right track.
Comment #23
pwolanin commentedoops - uploaded one with a bad date token.
Comment #25
pwolanin commentedThis patch removes the failing tests - I think they were invalid since there is no indication in the API that I should be able to add a file with query parameters.
Comment #26
damien tournoud commentedIf this is a date from format_date(), it's already HTML, so filter_xss() was correct.
We probably just need to make those tests generate absolute URLs for the test CSS and JS files with query strings, right?
Comment #27
pwolanin commentedOne is supposed to be passing file names into drupal_add_js and drupal_add_css. As we discussed in IRC, there are cases where we cannot know whether ? and & is indicating a query string or is part of a path or file name.
In this case, FILE names (on disk) cannot meaningfully have query strings, so I think encoding them is correct.
Comment #28
damien tournoud commentedWe have an 'external' option to drupal_add_js() and drupal_add_css(). I think that's what the test wanted to confirm.
Comment #29
pwolanin commented@Damien - ok, then we need to rework the test.
Comment #30
pwolanin commentedCNW for test fix ups.
Comment #31
pwolanin commentedpatch doesn't apply cleanly
Comment #32
pwolanin commentedNow with fixed tests.
Comment #33
scor commentedDamZ's comment in #26 still need to be addressed
Comment #34
pwolanin commented@scor - $date is a unix timestamp (though can possibly be user input).
Comment #35
scor commented@damZ: $date comes from the snippet above posted by pwolanin, i.e. not coming from format_date().
Comment #36
scor commentedwith DamZ's comments addressed, I meant to RTBC this.
Comment #37
dries commentedCommitted to CVS HEAD. Yay. :)