• Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
    Dedicated community for Japanese speakers
  • 한국 커뮤니티
    Dedicated community for Korean speakers
Exit
0

Does CFHTTP Handle File Attachments Wrong?

Contributor ,
Nov 29, 2021 Nov 29, 2021

Copy link to clipboard

Copied

I recently ran into an issue when interacting with Mailgun's API via CFHTTP whenever we attempted to send a file attachment.  The problem is that the recipient's email attachment file name always contains the full path of the file as passed to the cfhttparam file attribute. 

 

For example, if my actual filename was "Sample_Adobe_PDF_Document.pdf", Mailgun would send the attachment as "c:myfilesdocumentsSample_Adobe_PDF_Document.pdf".  Weird right?

 

I created a dummy API endpoint on beeceptor.com to see what CFHTTP was sending Mailgun, and this is the header that ColdFusion sends:

 

Content-Disposition: form-data; name="attachment"; filename="c:\myFiles\documents\Sample_Adobe_PDF_Document.pdf"
Content-Type: application/pdf

 


At first I figured this was a problem with Mailgun and that they weren't properly parsing the filename, from the POST data.  However, when I look at the web specifications for Content-Disposition Filename,  it says:
"Is followed by a string containing the original name of the file transmitted. The filename is always optional and must not be used blindly by the application: path information should be stripped, and conversion to the server file system rules should be done. This parameter provides mostly indicative information. When used in combination with Content-Disposition: attachment, it is used as the default filename for an eventual "Save As" dialog presented to the user"

 

ColdFusion requires the full path of the file be used in cfhttparam, so I don't think this is a mistake from my end.  It also doesn't make sense for ACF to reveal the full internal path of the file in a POST request. Some might argue that sending this data is a security concern.

I tested this in ACF 2016, ACF 2018, and ACF 2021. All versions include the full path of the file in the POST request.

What do you think?  Let me know if you think this is a bug and I'll create a ticket.

Views

778

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 1 Correct answer

Contributor , Jan 21, 2022 Jan 21, 2022

Thanks for putting together the example, BKBK.  The problem is that Adobe isn't following the spec when it generates the Content-Disposition Filename. It outputs the full path of the file like this:
Content-Disposition: form-data; name="attachment"; filename="C:\helloworld.txt" 
When it should output like this:
Content-Disposition: form-data; name="attachment"; filename="helloworld.txt" 
Spec Reference

There's no doubt you can extract just the filename if you're working with a system you control.  Ho

...

Votes

Translate

Translate
Community Expert ,
Nov 30, 2021 Nov 30, 2021

Copy link to clipboard

Copied

That suggests you're passing the value

filename="c:\myFiles\documents\Sample_Adobe_PDF_Document.pdf"

in the cfhttpparam header tag. Well, you shouldn't. As you yourself point out, it could indeed be a security risk.

 

You could just pass the file's name, literally:

filename="Sample_Adobe_PDF_Document.pdf"

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Contributor ,
Nov 30, 2021 Nov 30, 2021

Copy link to clipboard

Copied

Thanks @BKBK.  I wish I could do just that.  However CFHTTPPARAM doesn't allow the `filename` attribute and the docs specify that the `file` attribute must be the full path to the actual file on disk:
"Applies to File type; ignored for all other types. The absolute path to the file that is sent in the request body."

cfhttpparam( 
  name="attachment", 
  type="file", 
  file="C:\myFiles\documents\Sample_Adobe_PDF_Document.pdf" 
);

 FYI Lucee handles files in cfhttparam properly and creates the right filename attribute in the request:

Content-Disposition: form-data; name="attachment"; filename="Sample_Adobe_PDF_Document.pdf"
Content-Type: application/pdf

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Dec 05, 2021 Dec 05, 2021

Copy link to clipboard

Copied

I have a question or two.

  1. Does sending an attachment like that actually work?
  2. If so, could you please share the cfhttp/cfhttpparam that works.

 

The reason why I ask is this: it is unnecessary to pass the full file-path in the Content-Disposition header. That is because this header doesn't do the data transfer. It simply informs the receiver to expect the data as key-value pairs from a form. So a file-name, xyz.pdf, is sufficient.

 

I suspect Adobe ColdFusion and Lucee are doing it in essentially the same way. The way I see it, neither the ACF code nor the Lucee code you've shown will transfer a file! They're both headers, the announcers before the show. 🙂

 

I cannot remember sending files in this way. But I am guessing you could do so in one of two ways:

  • via a form
<cfset filename="Unleash the Ideavirus - Seth Godin.pdf">
<cfset filepath="C:\Users\BKBK\Desktop\Unleash the Ideavirus - Seth Godin.pdf">
<!--- Read file as binary data --->
<cffile action="readBinary" file="#filepath#" variable="attachedFile">
<!--- Convert binary to Base64 string so we can send it via a form --->
<!--- Alternative: convert to Hex instead of Base 64 --->
<cfset attachedFile=binaryEncode(attachedFile, "Base64")>

<cfhttp method="post">
    <!--- Tells the recipient to expect the data via a form, as key-value pairs  --->
    <cfhttpparam type="header" name="Content-Disposition" value="form-data; name='attachment'; filename=#filename#">
    <!--- Tells the recipient that content is PDF --->
    <cfhttpparam type="header" name="Content-Type" value="application/pdf"/>

    <!--- Sends the actual bytes of the file, as Base 64 string --->
    <cfhttpparam type="formfield" name="attachment" value="#attachedFile#"/>
</cfhttp>

The recipient will receive the file as the value of form.attachment. Recipient will then have to convert from Base64 back to Binary.

 

  • via a file embedded as data in the request body
<cfset filepath="C:\Users\BKBK\Desktop\Unleash the Ideavirus - Seth Godin.pdf">

<cfhttp method="post">
<!--- Tells the recipient to expect content of PDF type --->
<cfhttpparam type="header" name="Content-Type" value="application/pdf" >
<!--- Sends the file in the request body--->
<cfhttpparam type="file" file="#filepath#" name="attachment" mimetype="application/pdf">
</cfhttp>

 

 

 

 

 

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Contributor ,
Dec 14, 2021 Dec 14, 2021

Copy link to clipboard

Copied

@BKBK, my responses to your questions are below:

 

  1. Does sending an attachment like that actually work?
    Absolutely.  See https://cfdocs.org/cfhttpparam (type: file) for details

  2. If so, could you please share the cfhttp/cfhttpparam that works.
    Sure thing, you'll need to create a dummy endpoint (I like Beeceptor) and update the URL as well as the path to the file you actually want to upload.  For example, just create a simple txt file.

 

 

<cfscript>
cfhttp(
    method="POST",
    url="https://angrysam.free.beeceptor.com", // create your own endpoint on https://beeceptor.com/
    result="result"
) {
    cfhttpparam( 
        name="attachment", 
        type="file", 
        file="C:\helloworld.txt" // replace with a path to a real file on your system
    );
}

writedump( result );
</cfscript>​

 

If you look at the data Beeceptor receives, you'll see your server's full path was revealed like this:
Content-Disposition: form-data; name="attachment"; filename="C:\helloworld.txt" 
Lucee follows the spec correctly and will use this header instead:
Content-Disposition: form-data; name="attachment"; filename="helloworld.txt" 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Dec 15, 2021 Dec 15, 2021

Copy link to clipboard

Copied

Thanks for the information.

I am having another look.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Dec 17, 2021 Dec 17, 2021

Copy link to clipboard

Copied

Phew! Now, a bit of breathing space amid the Log4J zero-day troubles.

I have been able to create a test in which the file-path doesn't appear in the Content-Disposition header.

The test:

1) Create the directories

c:\filePost\senderFiles\

and

c:\filePost\receiverFiles\

2) Place a file, testFile.txt in c:\filePost\senderFiles\

3) Create the following directory (uder the web root): /wwwroot/filePost/

Place the following 2 CFM files in /wwwroot/filePost/

 

<!--- fileSender.cfm --->
<cfset filepath="C:\filePost\senderFiles\testFile.txt">

<cfhttp url="http://localhost:8500/filePost/fileRecipient.cfm" method="post" result="res" multipart="true">
<cfhttpparam type="file" file="#filepath#" name="attachment" mimetype="text/html">
</cfhttp>

<!--- Result of cfhttp post --->
<cfdump var="#res#" >

 

 

 

<!--- fileRecipient.cfm --->
<cftry>
    <!--- Dump request data received from post --->
    <cfdump var="#getHttpRequestData()#" format="html" output="C:\filePost\receiverFiles\getHttpRequestDataStruct.html" >

    <!--- Dump form struct received --->
    <cfdump var="#form#" format="html" output="C:\filePost\receiverFiles\formStruct.html">

    <!--- Write the recieved file to disk --->
    <cffile action="upload" destination="C:\filePost\receiverFiles\receivedFile.txt" filefield="attachment" nameconflict="overwrite" >

<cfcatch type="any" >
    <cfdump var="#cfcatch#" format="html" output="C:\filePost\receiverFiles\error.html">
</cfcatch>
</cftry>

 

 

4) Launch fileSender.cfm in the browser. That is, something like, http://127.0.0.1:8500/filePost/fileSender.cfm
5) Examine the results. If all goes well, several things will happen:
- the text file will be posted.;
- the new files receivedFile.txt, getHttpRequestDataStruct.html and formStruct.html will be written in c:\filePost\receiverFiles\

If you examine getHttpRequestDataStruct.html you will see that it does not contain the path of the sent file. In addition, formStruct.html shows that the receiver automatically saves the incoming file in the system's temp directory

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Contributor ,
Jan 21, 2022 Jan 21, 2022

Copy link to clipboard

Copied

Thanks for putting together the example, BKBK.  The problem is that Adobe isn't following the spec when it generates the Content-Disposition Filename. It outputs the full path of the file like this:
Content-Disposition: form-data; name="attachment"; filename="C:\helloworld.txt" 
When it should output like this:
Content-Disposition: form-data; name="attachment"; filename="helloworld.txt" 
Spec Reference

There's no doubt you can extract just the filename if you're working with a system you control.  However, I have encountered issues with 3rd party APIs (e.g. Mailgun) that don't parse the filename and wind up including the path in the final file. 

I contacted Adobe and I am happy to announce that they have a working hotfix for ACF 2018 that I have tested thoroughly on top of update 13 in development and production.   Hopefully Adobe will release this fix in the next official update for 2018 and 2021, but in the meantime, if anyone else is struggling with the issue, please reach out to ColdFusion support and ask for hf201800-4212578

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jan 22, 2022 Jan 22, 2022

Copy link to clipboard

Copied

LATEST

Thanks for sharing that.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Resources
Documentation