Pete Freitag Pete Freitag

Tips for Secure File Uploads with ColdFusion

Updated on December 07, 2023
By Pete Freitag
coldfusion

Allowing someone to upload a file to your ColdFusion or Lucee server is a common requirement, but also a very risky operation. So here are some security tips to help you write secure file upload code in ColdFusion.

Don't rely on cffile accept attribute

The accept attribute gives a terrible false sense of security. Every time I present on CFML Security I ask the question: If I have this code is there any way I could upload a CFM file?.

<cffile action="upload"
  filefield="photo"
  accept="image/gif,image/jpeg"
  destination="#ExpandPath("./photos/")#">

The answer is YES, often to the surprise of most!

The cffile accept attribute uses the mime type that your browser sends to the server. Read that again... your browser tells cffile what the mime type is. It's very easy to spoof the mime type. For example:

<cfhttp url="http://target.example.com/upload" method="post">
 <cfhttpparam file="#ExpandPath("badstuff.cfm")#"
  mimetype="image/gif" 
  type="file"
  name="photo">
</cfhttp>

For this reason you need to ensure that cffile.serverFileExt is of an extension you allow, and one that your server will not execute.

Use a file extension allowlist rather than a denylist, in other words you don't just check to make sure it is not a .cfm, make sure it is only one of: "jpg,png,gif". This way if someone installs PHP on your server, you don't have to update the code to block that file extension as well.

Validate that the File Extension matches File Format

You can use a Java API like JHOVE which reads the file contents to validate that it is of the asserted file format. It supports jpg, gif, pdf, tiff, and more.

In addition CF8 has the IsImageFile("path") and IsPDFFile("path") functions you could use. If you do use IsImageFile just make sure that you have upgraded your JVM to one that doesn't have the issue that can cause an image file to crash your server. See Mark Kruger's blog entry for details.

Always upload to a temp directory outside of the Web Root

Suppose I ran the same hack above with cfhttp but you now have code in place to delete the file if the extension is incorrect. There is a slight chance that I could execute that file before you can delete it if you uploaded it into the web root (and I could predict where it would be placed).

Once you have validated the upload, you can move it to its desired location.

Keep uploaded files outside the web root

If possible keep uploaded files outside of the web root and serve them with cfcontent. In some cases this is not possible, but seriously consider this as it does ease the risk significantly.

Remove execute permissions from upload directories

The reason for this should be obvious, but is something we often forget to do.

Upload to a static content server

If possible upload content to a server other than the application server, a server that only serves static content (for example Amazon S3).

Don't trust on the client supplied file name

The client supplied file name could possibly contain SQL Injection, cross site scripting, or CRLF Injection.

It's best to strip out non alpha numeric characters (perhaps with the exception of dash and underscore).

ColdFusion Administrator Settings

There are a few Administrator Settings that you should pay attention to related to file uploads (and large HTTP POST operations). They are under Server Settings » Settings under the heading Request Size Limits:

CF Administrator Request Size Limits

The first setting is the maximum size of a POST, and therefor also a file upload. The default 100mb is probably bigger than needed for most web apps, you can lower it to mitigate DOS potential. Chances are your web server is also capable of limiting the post size, on apache you can use the LimitRequestBody directive to do this.

The next setting Request Throttle Threshold should probably be lowered to 1MB, this puts any request larger than 1mb into a throttle for synchronous processing.

The third setting Request Throttle Memory is the maximum size of request throttle queue. The default is kind of high, if you don't have a lot of large file uploads going on at the same time this should be lowered to say 50mb (it shouldn't be lower than the Maximum size of post data, or the Request Throttle Threshold, but it could be equal to the max size.). Consider that on a 32bit server, the max JVM size is typically not much bigger than 1GB, you could allow 1/5th of your server resources to be consumed by file uploads with the default setting.

Sandboxes

If you are using the Enterprise edition of ColdFusion you can setup a sandbox for your file upload directory, and remove execute permission. This only applies to ColdFusion template execution (not PHP scripts for example).

Restrict using Web Server

Use you should limit your uploads directory to only allow static files to be requested. For example on IIS you can remove the handler mappings for CF, and then use Request Filtering to limit file extensions to a specific allowlist, so that IIS will reject any request under /images/ that is not a .gif, .png, or .jpg for example.


Tools that can help

My company Foundeo makes some tools that can help you out here. First FuseGuard Web App Firewall for ColdFusion allows you to set an allow list of file extensions. FuseGuard runs in your Application.cfc or Application.cfm file to inspect, log and block requests before they hit your application code. This means that if someone tries to upload a cfm file to your ColdFusion application, and FuseGuard is running it would block the request, even if your application code would have allowed it. It's always best to fix your code as well, but running FuseGuard can add a nice layer of defense in front of your CFML applications.

Another tool that might help is a code security scanner, Fixinator. With Fixinator you can scan your source code for file upload vulnerabilities. You can even run Fixinator in a CI environment, so that it can scan your CFML code for security issues automatically every time you commit to version control.

Do you have any additional tips?



security cffile upload file xss

Tips for Secure File Uploads with ColdFusion was first published on June 24, 2009.

If you like reading about security, cffile, upload, file, or xss then you might also like:

Fixinator

The Fixinator Code Security Scanner for ColdFusion & CFML is an easy to use security tool that every CF developer can use. It can also easily integrate into CI for automatic scanning on every commit.


Try Fixinator

CFBreak
The weekly newsletter for the CFML Community


Comments

This may be a silly question, but if someone is uploading from a Mac, will it still be able to verify from the extension if there isn't one?
by pedrom40 on 06/24/2009 at 2:05:59 PM UTC
I think the browser may be able to send the appropriate mime type if there is no file extension (I would have to look into that further), but remember you can't trust what the browser sends anyways, it could be spoofed.
by Pete Freitag on 06/24/2009 at 2:10:05 PM UTC
Pete, excellent tips. Disabling execute permissions on uploads directory is really nice.
by Ben Nadel on 06/24/2009 at 3:48:35 PM UTC
Great set of tips; I'd also suggest that if you have Apache, watch out for any uploaded files that have multiple file extensions (e.g., file.php.html). By default, Apache will run the file with the PHP handler even though the last extension is something else. See http://www.mollerus.net/tom/blog/2009/02/watch_out_for_apache_handling_of_files_with_multip.html
by Tom Mollerus on 06/24/2009 at 5:27:31 PM UTC
Thanks Ben!
by Pete Freitag on 06/24/2009 at 5:28:22 PM UTC
@Tom Great tip, thanks for posting
by Pete Freitag on 06/24/2009 at 5:29:58 PM UTC
I'm revisiting an app that allows customer file uploading, and one approach I'm considering is using CreatUUID() to generate a server side file name and stick the customer provided filename in a related database entry (going through cfqueryparam, of course).
by jason olmsted on 06/24/2009 at 8:42:28 PM UTC
Pete, great post. Thanks for the tips. I've been meaning to blog about this myself. You beat me to it. But you also covered quite a lot that I didn't know, so thank you for that. Very enlightening.
by Jason Dean on 06/26/2009 at 5:51:03 PM UTC
When I upload files, there are two things I always to before it gets to the action page (or code block). First, I use JavaScript to inspect the file extension and act accordingly. Second, I do the same extension validation on the server side. If all is well, then the suggestions offered here would be good!
by Mike Letson on 06/27/2009 at 9:30:53 AM UTC
@jason olmsted - Make sure you sanitize the customer supplied file name before sticking it in the db, as they could potentially include something to trigger XSS, you can use this regex: ReReplace(fileNane, "[^a-zA-Z0-9_-]", "", "ALL"), and ofcourse still use cfqueryparam (always use it :)

@jason dean - glad you found it useful, feel free to post about this on your blog as well. The more people who read about it the better.

@mike letson - Using JavaScript validation is good for user experience but doesn't have any effect on security.
by Pete Freitag on 06/30/2009 at 10:24:13 AM UTC
Great tips, thanks for sharing, Pete. I'm comforted by the fact that I tend to follow all suggestions you've made, with the exception of a static content server. I really do like that idea and intend to leverage Amazon S3 for static content whenever possible in the future.

It's worth noting that you could achieve similar security on your own server, if needed, by leveraging Apache and creating a static content virtual host. You can have that virtual host limit file extensions and/or mime types and rewrite to 403-forbidden any suspicious requests.
by Jamie Krug on 06/30/2009 at 10:28:49 AM UTC
@Jamie thanks, yes that is worth noting. I didn't intend to suggest that S3, or some third party CDN was the only way.
by Pete Freitag on 06/30/2009 at 10:36:20 AM UTC
Just so I'm clear: the problem isn't really that they can upload a CFML file, it's that they can predict the URL afterwards in order to execute it, right?

If so, placing an Application.cfc / Application.cfm file in your images directory that blocks requests would be sufficient to prevent execution?

Or am I missing something?
by Sean Corfield on 07/01/2009 at 4:15:00 PM UTC
@Sean - They don't necessarily have to be able to predict it, the application may disclose it in an image tag, or link.

Adding Application.cfc/cfm is a good idea, but it can only block ColdFusion requests, I could upload a .jsp file instead, or some other file type that might be executed server side.
by Pete Freitag on 07/02/2009 at 8:08:56 AM UTC
(sorry forgot to subscribe, I'm way interested in feedback)
by Nathan Dye on 07/02/2009 at 10:22:55 PM UTC
@Sean,
You make an excellent point I haven't thought about. You can effectively disable CF from ever executing from that folder with the right application logic. However, it still leaves open the possibility that bad files can 'exist' on the server to be exploited outside of being executed by CF.
by Michael Williams on 07/09/2009 at 10:01:37 PM UTC
@Pete, How could I do a good file extension test before the file itself has been uploaded by CFFILE even using all the security mesures pointed here? Or the file will be uploaded first, then tested for extension and finally deleted by CFFILE DELETE? Thanks.
by Marllon Capdeville on 07/31/2009 at 9:11:49 AM UTC
@Marllon:

I'm fairly certain you'll need to upload the file first. You could use some JavaScript to check the extension, but since that's client side it could always be spoofed. You don't have definitive control/evidence until the file is server-side.

Check out Pete's "Always upload to a temp directory outside of the Web Root" section, above.
by Jamie Krug on 07/31/2009 at 9:19:00 AM UTC
@Marllon Yes as Jamie mentioned you need to upload the file to a dir outside of the web root and then check the file extension. Otherwise the only way you could do this before calling cffile would be to use a Servlet Filter, or something else that runs before the CFML engine.
by Pete Freitag on 07/31/2009 at 11:30:50 AM UTC
I'd just like to point out, in response to the first commenter, that Mac OS X files do indeed have file extensions. By default they are hidden to the user but upon sending a file out (as in this case) they do apply.
by Jordan on 02/24/2010 at 1:35:17 PM UTC
I just wanted to chime in to remind people that the same goes for emails which attachments that are downloaded by CFpop. I have a system which acts as a web client for accessing email ( <gasp> and saves the attachments into a pub directory</gasp> ), and I basically crapped myself when I realized that I was doing no checking, and someone could have simply emailed us a CFM file. My two faults here are A: serving attachments publicly and B: Not filtering attachments. Very old app, but Jeeze! Horrible.

-Brian
by Brian H.. on 03/02/2010 at 7:12:59 PM UTC