diff --git a/attachment.php b/attachment.php
deleted file mode 100644
index 05e256a42a980c0c15e5469167af2a047952718c..0000000000000000000000000000000000000000
--- a/attachment.php
+++ /dev/null
@@ -1,36 +0,0 @@
-<?php
-/*********************************************************************
-    attachment.php
-
-    Attachments interface for clients.
-    Clients should never see the dir paths.
-
-    Peter Rotich <peter@osticket.com>
-    Copyright (c)  2006-2013 osTicket
-    http://www.osticket.com
-
-    Released under the GNU General Public License WITHOUT ANY WARRANTY.
-    See LICENSE.TXT for details.
-
-    vim: expandtab sw=4 ts=4 sts=4:
-**********************************************************************/
-require('secure.inc.php');
-require_once(INCLUDE_DIR.'class.attachment.php');
-//Basic checks
-if(!$thisclient
-        || !$_GET['id']
-        || !$_GET['h']
-        || !($attachment=Attachment::lookup($_GET['id']))
-        || !($file=$attachment->getFile()))
-    Http::response(404, __('Unknown or invalid file'));
-
-//Validate session access hash - we want to make sure the link is FRESH! and the user has access to the parent ticket!!
-$vhash=md5($attachment->getFileId().session_id().strtolower($file->getKey()));
-if(strcasecmp(trim($_GET['h']),$vhash)
-        || !($ticket=$attachment->getTicket())
-        || !$ticket->checkUserAccess($thisclient))
-    Http::response(404, __('Unknown or invalid file'));
-//Download the file..
-$file->download();
-
-?>
diff --git a/file.php b/file.php
new file mode 100644
index 0000000000000000000000000000000000000000..e5dd71ed8069048ce1de64a95515027bf6243233
--- /dev/null
+++ b/file.php
@@ -0,0 +1,39 @@
+<?php
+/*********************************************************************
+    file.php
+
+    File download facilitator for clients
+
+    Peter Rotich <peter@osticket.com>
+    Jared Hancock <jared@osticket.com>
+    Copyright (c)  2006-2014 osTicket
+    http://www.osticket.com
+
+    Released under the GNU General Public License WITHOUT ANY WARRANTY.
+    See LICENSE.TXT for details.
+
+    vim: expandtab sw=4 ts=4 sts=4:
+**********************************************************************/
+require('client.inc.php');
+require_once(INCLUDE_DIR.'class.file.php');
+
+//Basic checks
+if (!$_GET['key']
+    || !$_GET['signature']
+    || !$_GET['expires']
+    || !($file = AttachmentFile::lookup($_GET['key']))
+) {
+    Http::response(404, __('Unknown or invalid file'));
+}
+
+// Validate session access hash - we want to make sure the link is FRESH!
+// and the user has access to the parent ticket!!
+if ($file->verifySignature($_GET['signature'], $_GET['expires'])) {
+    if (($s = @$_GET['s']) && strpos($file->getType(), 'image/') === 0)
+        $file->display($s);
+
+    // Download the file..
+    $file->download(@$_GET['disposition'] ?: false, $_GET['expires']);
+}
+// else
+Http::response(404, __('Unknown or invalid file'));
diff --git a/image.php b/image.php
deleted file mode 100644
index 5b7f27283ba23175ff12772f4212a41859ea3e18..0000000000000000000000000000000000000000
--- a/image.php
+++ /dev/null
@@ -1,31 +0,0 @@
-<?php
-/*********************************************************************
-    image.php
-
-    Simply downloads the file...on hash validation as follows;
-
-    * Hash must be 64 chars long.
-    * First 32 chars is the perm. file hash
-    * Next 32 chars  is md5(file_id.session_id().file_hash)
-
-    Peter Rotich <peter@osticket.com>
-    Copyright (c)  2006-2013 osTicket
-    http://www.osticket.com
-
-    Released under the GNU General Public License WITHOUT ANY WARRANTY.
-    See LICENSE.TXT for details.
-
-    vim: expandtab sw=4 ts=4 sts=4:
-**********************************************************************/
-
-require('client.inc.php');
-require_once(INCLUDE_DIR.'class.file.php');
-$h=trim($_GET['h']);
-//basic checks
-if(!$h  || strlen($h)!=64  //32*2
-        || !($file=AttachmentFile::lookup(substr($h,0,32))) //first 32 is the file hash.
-        || strcasecmp($h, $file->getDownloadHash())) //next 32 is file id + session hash.
-    Http::response(404, __('Unknown or invalid file'));
-
-$file->display();
-?>
diff --git a/include/ajax.draft.php b/include/ajax.draft.php
index f727e2cc9a10040786f6abb3502a8a21f7e04806..091632891e0d5d065048bdd8859095f867b1880e 100644
--- a/include/ajax.draft.php
+++ b/include/ajax.draft.php
@@ -129,7 +129,7 @@ class DraftAjaxAPI extends AjaxController {
 
         echo JsonDataEncoder::encode(array(
             'content_id' => 'cid:'.$f->getKey(),
-            'filelink' => sprintf('image.php?h=%s', $f->getDownloadHash())
+            'filelink' => $f->getDownloadUrl(false, 'inline'),
         ));
     }
 
@@ -309,7 +309,7 @@ class DraftAjaxAPI extends AjaxController {
         );
         while (list($id, $type) = db_fetch_row($res)) {
             $f = AttachmentFile::lookup($id);
-            $url = 'image.php?h='.$f->getDownloadHash();
+            $url = $f->getDownloadUrl();
             $files[] = array(
                 'thumb'=>$url.'&s=128',
                 'image'=>$url,
diff --git a/include/class.attachment.php b/include/class.attachment.php
index d562b31a095fa69251f62af687d14f40dfda0243..3f2101e18be4a18695f8f67a3eb5289006c8f8fc 100644
--- a/include/class.attachment.php
+++ b/include/class.attachment.php
@@ -171,15 +171,15 @@ class GenericAttachments {
     function _getList($separate=false, $inlines=false) {
         if(!isset($this->attachments)) {
             $this->attachments = array();
-            $sql='SELECT f.id, f.size, f.`key`, f.name, a.inline '
+            $sql='SELECT f.id, f.size, f.`key`, f.signature, f.name, a.inline '
                 .' FROM '.FILE_TABLE.' f '
                 .' INNER JOIN '.ATTACHMENT_TABLE.' a ON(f.id=a.file_id) '
                 .' WHERE a.`type`='.db_input($this->getType())
                 .' AND a.object_id='.db_input($this->getId());
             if(($res=db_query($sql)) && db_num_rows($res)) {
                 while($rec=db_fetch_array($res)) {
-                    $rec['download'] = AttachmentFile::getDownloadForIdAndKey(
-                        $rec['id'], $rec['key']);
+                    $rec['download_url'] = AttachmentFile::generateDownloadUrl(
+                        $rec['id'], $rec['key'], $rec['signature']);
                     $this->attachments[] = $rec;
                 }
             }
diff --git a/include/class.draft.php b/include/class.draft.php
index cdb5d43f440081d3e047993dd0df006cf23c39d6..3235a9ff92a5e7f967a73d78811568951975ebec 100644
--- a/include/class.draft.php
+++ b/include/class.draft.php
@@ -61,7 +61,7 @@ class Draft {
     }
 
     function setBody($body) {
-        // Change image.php urls back to content-id's
+        // Change file.php urls back to content-id's
         $body = Format::sanitize($body, false);
         $this->ht['body'] = $body;
 
diff --git a/include/class.faq.php b/include/class.faq.php
index 0395b4968671f9a487167443d66ef242d7f9da04..5df6655d54f90e7eb50a5f5fb22648dedc92ed1e 100644
--- a/include/class.faq.php
+++ b/include/class.faq.php
@@ -61,7 +61,7 @@ class FAQ {
     function getQuestion() { return $this->ht['question']; }
     function getAnswer() { return $this->ht['answer']; }
     function getAnswerWithImages() {
-        return Format::viewableImages($this->ht['answer'], ROOT_PATH.'image.php');
+        return Format::viewableImages($this->ht['answer']);
     }
     function getSearchableAnswer() {
         return ThreadBody::fromFormattedText($this->ht['answer'], 'html')
@@ -198,12 +198,11 @@ class FAQ {
         if(($attachments=$this->attachments->getSeparates())) {
             foreach($attachments as $attachment ) {
             /* The h key must match validation in file.php */
-            $hash=$attachment['key'].md5($attachment['id'].session_id().strtolower($attachment['key']));
             if($attachment['size'])
                 $size=sprintf('&nbsp;<small>(<i>%s</i>)</small>',Format::file_size($attachment['size']));
 
-            $str.=sprintf('<a class="Icon file no-pjax" href="file.php?h=%s" target="%s">%s</a>%s&nbsp;%s',
-                    $hash, $target, Format::htmlchars($attachment['name']), $size, $separator);
+            $str.=sprintf('<a class="Icon file no-pjax" href="%s" target="%s">%s</a>%s&nbsp;%s',
+                    $attachment['download_url'], $target, Format::htmlchars($attachment['name']), $size, $separator);
 
             }
         }
diff --git a/include/class.file.php b/include/class.file.php
index b38ddb2dc6e895642403a394a21d632223b454cc..ce662085ae0b62af1163ce451bca4b08bd31e8ca 100644
--- a/include/class.file.php
+++ b/include/class.file.php
@@ -107,19 +107,6 @@ class AttachmentFile {
         return $this->ht['created'];
     }
 
-    static function getDownloadForIdAndKey($id, $key) {
-        return strtolower($key . md5($id.session_id().strtolower($key)));
-    }
-
-
-    /**
-     * Retrieve a signature that can be sent to scp/file.php?h= in order to
-     * download this file
-     */
-    function getDownloadHash() {
-        return self::getDownloadForIdAndKey($this->getId(), $this->getKey());
-    }
-
     function open() {
         return FileStorageBackend::getInstance($this);
     }
@@ -200,13 +187,70 @@ class AttachmentFile {
         exit();
     }
 
-    function download() {
+    function getDownloadUrl($minage=false, $disposition=false, $handler=false) {
+        // XXX: Drop this when AttachmentFile goes to ORM
+        return static::generateDownloadUrl($this->getId(),
+            strtolower($this->getKey()), $this->getSignature(), $minage,
+            $disposition, $handler);
+    }
+
+    static function generateDownloadUrl($id, $key, $hash, $minage=false,
+        $disposition=false, $handler=false
+    ) {
+        // Expire at the nearest midnight, allowing at least 12 hours access
+        $minage = $minage ?: 43200;
+        $gmnow = Misc::gmtime() + $minage;
+        $expires = $gmnow + 86400 - ($gmnow % 86400);
+
+        // Generate a signature based on secret content
+        $signature = static::_genUrlSignature($id, $key, $hash, $expires);
+
+        $handler = $handler ?: ROOT_PATH . 'file.php';
+
+        // Return sanitized query string
+        $args = array(
+            'key' => $key,
+            'expires' => $expires,
+            'signature' => $signature,
+        );
+
+        if ($disposition)
+            $args['disposition'] = $disposition;
+
+        return $handler . '?' . http_build_query($args);
+    }
+
+    function verifySignature($signature, $expires) {
+        $gmnow = Misc::gmtime();
+        if ($expires < $gmnow)
+            return false;
+
+        $check = static::_genUrlSignature($this->getId(), $this->getKey(),
+            $this->getSignature(), $expires);
+        return $signature == $check;
+    }
+
+    static function _genUrlSignature($id, $key, $signature, $expires) {
+        $pieces = array(
+            'Host='.$_SERVER['HTTP_HOST'],
+            'Path='.ROOT_PATH,
+            'Id='.$id,
+            'Key='.strtolower($key),
+            'Hash='.$signature,
+            'Expires='.$expires,
+        );
+        return hash_hmac('sha1', implode("\n", $pieces), SECRET_SALT);
+    }
+
+    function download($disposition=false, $expires=false) {
+        $disposition = $disposition ?: 'attachment';
         $bk = $this->open();
-        if ($bk->sendRedirectUrl('inline'))
+        if ($bk->sendRedirectUrl($disposition))
             return;
-        $this->makeCacheable();
+        $ttl = ($expires) ? $expires - Misc::gmtime() : false;
+        $this->makeCacheable($ttl);
         Http::download($this->getName(), $this->getType() ?: 'application/octet-stream',
-            null, 'inline');
+            null, $disposition);
         header('Content-Length: '.$this->getSize());
         $this->sendData(false);
         exit();
diff --git a/include/class.format.php b/include/class.format.php
index 7ac9f1e297dd7022a1ee9e81545a71e9b04bc646..a124a577f60a0cc88beff06dce0c3953fa8d96d6 100644
--- a/include/class.format.php
+++ b/include/class.format.php
@@ -259,9 +259,10 @@ class Format {
     }
 
     function localizeInlineImages($text) {
-        // Change image.php urls back to content-id's
-        return preg_replace('/image\\.php\\?h=([\\w.-]{32})\\w{32}/',
-            'cid:$1', $text);
+        // Change file.php urls back to content-id's
+        return preg_replace(
+            '/src="(?:\/[^"]+?)?\/file\\.php\\?(?:\w+=[^&]+&(?:amp;)?)*?key=([^&]+)[^"]*/',
+            'src="cid:$1', $text);
     }
 
     function sanitize($text, $striptags=false) {
@@ -408,14 +409,14 @@ class Format {
     }
 
 
-    function viewableImages($html, $script='image.php') {
+    function viewableImages($html, $script=false) {
         return preg_replace_callback('/"cid:([\w._-]{32})"/',
         function($match) use ($script) {
             $hash = $match[1];
             if (!($file = AttachmentFile::lookup($hash)))
                 return $match[0];
-            return sprintf('"%s?h=%s" data-cid="%s"',
-                $script, $file->getDownloadHash(), $match[1]);
+            return sprintf('"%s" data-cid="%s"',
+                $file->getDownloadUrl(false, 'inline', $script), $match[1]);
         }, $html);
     }
 
diff --git a/include/class.forms.php b/include/class.forms.php
index f21f5f7974f6a64c6883cdeffbd1651e98bde261..e242a44ba40c77807e454be6f9b2313cabc6bb5f 100644
--- a/include/class.forms.php
+++ b/include/class.forms.php
@@ -1647,10 +1647,8 @@ class FileUploadField extends FormField {
     function display($value) {
         $links = array();
         foreach ($this->getFiles() as $f) {
-            $hash = strtolower($f['key']
-                . md5($f['id'].session_id().strtolower($f['key'])));
-            $links[] = sprintf('<a class="no-pjax" href="file.php?h=%s">%s</a>',
-                $hash, Format::htmlchars($f['name']));
+            $links[] = sprintf('<a class="no-pjax" href="%s">%s</a>',
+                Format::htmlchars($f['download_url']), Format::htmlchars($f['name']));
         }
         return implode('<br/>', $links);
     }
@@ -2096,6 +2094,7 @@ class FileUploadWidget extends Widget {
                     'name' => $file->getName(),
                     'type' => $file->getType(),
                     'size' => $file->getSize(),
+                    'download_url' => $file->getDownloadUrl(),
                 );
             }
         }
diff --git a/include/class.http.php b/include/class.http.php
index d45218051a12e3c9d5bbf1ddf24ade23d2760c2c..463387df54e148e0f164321159c203bd59c53540 100644
--- a/include/class.http.php
+++ b/include/class.http.php
@@ -63,14 +63,16 @@ class Http {
 
     function cacheable($etag, $modified, $ttl=3600) {
         // Thanks, http://stackoverflow.com/a/1583753/1025836
-        $last_modified = Misc::db2gmtime($modified);
-        header("Last-Modified: ".date('D, d M y H:i:s', $last_modified)." GMT", false);
+        // Timezone doesn't matter here — but the time needs to be
+        // consistent round trip to the browser and back.
+        $last_modified = strtotime($modified." GMT");
+        header("Last-Modified: ".date('D, d M Y H:i:s', $last_modified)." GMT", false);
         header('ETag: "'.$etag.'"');
         header("Cache-Control: private, max-age=$ttl");
-        header('Expires: ' . gmdate(DATE_RFC822, time() + $ttl)." GMT");
+        header('Expires: ' . gmdate('D, d M Y H:i:s', Misc::gmtime() + $ttl)." GMT");
         header('Pragma: private');
         if (@strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $last_modified ||
-            @trim($_SERVER['HTTP_IF_NONE_MATCH']) == $etag) {
+            @trim($_SERVER['HTTP_IF_NONE_MATCH'], '"') == $etag) {
                 header("HTTP/1.1 304 Not Modified");
                 exit();
         }
@@ -97,9 +99,8 @@ class Http {
 
     function download($filename, $type, $data=null, $disposition='attachment') {
         header('Pragma: private');
-        header('Expires: 0');
         header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
-        header('Cache-Control: private');
+        header('Cache-Control: private', false);
         header('Content-Type: '.$type);
         header(sprintf('Content-Disposition: %s; %s',
             $disposition,
diff --git a/include/class.page.php b/include/class.page.php
index c533617d6126b04668d5927bf43cacf875c34cb8..a6faf5f019762ef075005a1e48f2d911c03e5613 100644
--- a/include/class.page.php
+++ b/include/class.page.php
@@ -71,7 +71,7 @@ class Page {
         return $this->ht['body'];
     }
     function getBodyWithImages() {
-        return Format::viewableImages($this->getBody(), ROOT_PATH.'image.php');
+        return Format::viewableImages($this->getBody());
     }
 
     function getNotes() {
diff --git a/include/class.thread.php b/include/class.thread.php
index b6fcf78c304d5c466269213b594f4baa16dae1e4..6a7e498a1f34901727152ba48335f1f79aeddfe1 100644
--- a/include/class.thread.php
+++ b/include/class.thread.php
@@ -579,7 +579,7 @@ Class ThreadEntry {
             return $this->attachments;
 
         //XXX: inner join the file table instead?
-        $sql='SELECT a.attach_id, f.id as file_id, f.size, lower(f.`key`) as file_hash, f.name, a.inline '
+        $sql='SELECT a.attach_id, f.id as file_id, f.size, lower(f.`key`) as file_hash, f.`signature` as file_sig, f.name, a.inline '
             .' FROM '.FILE_TABLE.' f '
             .' INNER JOIN '.TICKET_ATTACHMENT_TABLE.' a ON(f.id=a.file_id) '
             .' WHERE a.ticket_id='.db_input($this->getTicketId())
@@ -587,19 +587,21 @@ Class ThreadEntry {
 
         $this->attachments = array();
         if(($res=db_query($sql)) && db_num_rows($res)) {
-            while($rec=db_fetch_array($res))
+            while($rec=db_fetch_array($res)) {
+                $rec['download_url'] = AttachmentFile::generateDownloadUrl(
+                    $rec['file_id'], $rec['file_hash'], $rec['file_sig']);
                 $this->attachments[] = $rec;
+            }
         }
 
         return $this->attachments;
     }
 
-    function getAttachmentUrls($script='image.php') {
+    function getAttachmentUrls() {
         $json = array();
         foreach ($this->getAttachments() as $att) {
             $json[$att['file_hash']] = array(
-                'download_url' => sprintf('attachment.php?id=%d&h=%s', $att['attach_id'],
-                    strtolower(md5($att['file_id'].session_id().$att['file_hash']))),
+                'download_url' => $att['download_url'],
                 'filename' => $att['name'],
             );
         }
@@ -612,14 +614,12 @@ Class ThreadEntry {
         foreach($this->getAttachments() as $attachment ) {
             if ($attachment['inline'])
                 continue;
-            /* The hash can be changed  but must match validation in @file */
-            $hash=md5($attachment['file_id'].session_id().$attachment['file_hash']);
             $size = '';
             if($attachment['size'])
                 $size=sprintf('<em>(%s)</em>', Format::file_size($attachment['size']));
 
-            $str.=sprintf('<a class="Icon file no-pjax" href="%s?id=%d&h=%s" target="%s">%s</a>%s&nbsp;%s',
-                    $file, $attachment['attach_id'], $hash, $target, Format::htmlchars($attachment['name']), $size, $separator);
+            $str.=sprintf('<a class="Icon file no-pjax" href="%s" target="%s">%s</a>%s&nbsp;%s',
+                    $attachment['download_url'], $target, Format::htmlchars($attachment['name']), $size, $separator);
         }
 
         return $str;
diff --git a/include/staff/settings-pages.inc.php b/include/staff/settings-pages.inc.php
index 9727bde4060beeaacce6169a375b87b0b5382aa9..3bf1c78776adc2bc90b9604175591bd3ff969202 100644
--- a/include/staff/settings-pages.inc.php
+++ b/include/staff/settings-pages.inc.php
@@ -135,7 +135,7 @@ $pages = Page::getPages();
                     echo $logo->getId(); ?>" <?php
                     if ($logo->getId() == $current)
                         echo 'checked="checked"'; ?>/>
-                <img src="image.php?h=<?php echo $logo->getDownloadHash(); ?>"
+                <img src="<?php echo $logo->getDownloadUrl(); ?>"
                     alt="Custom Logo" valign="middle"
                     style="box-shadow: 0 0 0.5em rgba(0,0,0,0.5);
                         margin: 0.5em; height: 5em;
diff --git a/js/filedrop.field.js b/js/filedrop.field.js
index 4eb5d27e91ebdb78033b0e6cdab7e4d20b57f0f8..63b4b456ab1cd2cbe93bdf5454c909c79c295ed0 100644
--- a/js/filedrop.field.js
+++ b/js/filedrop.field.js
@@ -180,11 +180,12 @@
       }
       if (file.id)
         filenode.data('fileId', file.id);
-      if (file.download)
+      if (file.download_url) {
         filenode.find('.filename').prepend(
           $('<a class="no-pjax" target="_blank"></a>').text(file.name)
-            .attr('href', 'file.php?h='+escape(file.download))
+            .attr('href', file.download_url)
         );
+      }
       else
         filenode.find('.filename').prepend($('<span>').text(file.name));
       this.$element.parent().find('.files').append(filenode);
diff --git a/kb/file.php b/kb/file.php
deleted file mode 100644
index 99664708a567a08d80eaca73ece27a7f9973f87a..0000000000000000000000000000000000000000
--- a/kb/file.php
+++ /dev/null
@@ -1,30 +0,0 @@
-<?php
-/*********************************************************************
-    file.php
-
-    Simply downloads the file...on hash validation as follows;
-
-    * Hash must be 64 chars long.
-    * First 32 chars is the perm. file hash
-    * Next 32 chars  is md5(file_id.session_id().file_hash)
-
-    Peter Rotich <peter@osticket.com>
-    Copyright (c)  2006-2013 osTicket
-    http://www.osticket.com
-
-    Released under the GNU General Public License WITHOUT ANY WARRANTY.
-    See LICENSE.TXT for details.
-
-    vim: expandtab sw=4 ts=4 sts=4:
-**********************************************************************/
-require('kb.inc.php');
-require_once(INCLUDE_DIR.'class.file.php');
-$h=trim($_GET['h']);
-//basic checks
-if(!$h  || strlen($h)!=64  //32*2
-        || !($file=AttachmentFile::lookup(substr($h,0,32))) //first 32 is the file hash.
-        || strcasecmp($h, $file->getDownloadHash())) //next 32 is file id + session hash.
-    Http::response(404, __('Unknown or invalid file'));
-
-$file->download();
-?>
diff --git a/scp/attachment.php b/scp/attachment.php
deleted file mode 100644
index 07f20981a19a982c3014033eab67465b9f5587a8..0000000000000000000000000000000000000000
--- a/scp/attachment.php
+++ /dev/null
@@ -1,31 +0,0 @@
-<?php
-/*********************************************************************
-    attachment.php
-
-    Handles attachment downloads & access validation.
-
-    Peter Rotich <peter@osticket.com>
-    Copyright (c)  2006-2013 osTicket
-    http://www.osticket.com
-
-    Released under the GNU General Public License WITHOUT ANY WARRANTY.
-    See LICENSE.TXT for details.
-
-    vim: expandtab sw=4 ts=4 sts=4:
-**********************************************************************/
-require('staff.inc.php');
-require_once(INCLUDE_DIR.'class.attachment.php');
-
-//Basic checks
-if(!$thisstaff || !$_GET['id'] || !$_GET['h']
-        || !($attachment=Attachment::lookup($_GET['id']))
-        || !($file=$attachment->getFile()))
-    Http::response(404, __('Unknown or invalid file'));
-
-//Validate session access hash - we want to make sure the link is FRESH! and the user has access to the parent ticket!!
-$vhash=md5($attachment->getFileId().session_id().strtolower($file->getKey()));
-if(strcasecmp(trim($_GET['h']),$vhash) || !($ticket=$attachment->getTicket()) || !$ticket->checkStaffAccess($thisstaff)) die(__('Access Denied'));
-
-//Download the file..
-$file->download();
-?>
diff --git a/scp/file.php b/scp/file.php
deleted file mode 100644
index 97687de0f0bb0a341ce895298f587891a9c179c0..0000000000000000000000000000000000000000
--- a/scp/file.php
+++ /dev/null
@@ -1,30 +0,0 @@
-<?php
-/*********************************************************************
-    file.php
-
-    Simply downloads the file...on hash validation as follows;
-
-    * Hash must be 64 chars long.
-    * First 32 chars is the perm. file hash
-    * Next 32 chars  is md5(file_id.session_id().file_hash)
-
-    Peter Rotich <peter@osticket.com>
-    Copyright (c)  2006-2013 osTicket
-    http://www.osticket.com
-
-    Released under the GNU General Public License WITHOUT ANY WARRANTY.
-    See LICENSE.TXT for details.
-
-    vim: expandtab sw=4 ts=4 sts=4:
-**********************************************************************/
-require('staff.inc.php');
-require_once(INCLUDE_DIR.'class.file.php');
-$h=trim($_GET['h']);
-//basic checks
-if(!$h  || strlen($h)!=64  //32*2
-        || !($file=AttachmentFile::lookup(substr($h,0,32))) //first 32 is the file hash.
-        || strcasecmp($file->getDownloadHash(), $h)) //next 32 is file id + session hash.
-    Http::response(404, __('Unknown or invalid file'));
-
-$file->download();
-?>
diff --git a/scp/image.php b/scp/image.php
deleted file mode 100644
index 4c4ddbfe6da36e21588c0359b96924c365fba64b..0000000000000000000000000000000000000000
--- a/scp/image.php
+++ /dev/null
@@ -1,34 +0,0 @@
-<?php
-/*********************************************************************
-    image.php
-
-    Simply downloads the file...on hash validation as follows;
-
-    * Hash must be 64 chars long.
-    * First 32 chars is the perm. file hash
-    * Next 32 chars  is md5(file_id.session_id().file_hash)
-
-    Peter Rotich <peter@osticket.com>
-    Copyright (c)  2006-2013 osTicket
-    http://www.osticket.com
-
-    Released under the GNU General Public License WITHOUT ANY WARRANTY.
-    See LICENSE.TXT for details.
-
-    vim: expandtab sw=4 ts=4 sts=4:
-**********************************************************************/
-
-require('staff.inc.php');
-require_once(INCLUDE_DIR.'class.file.php');
-$h=trim($_GET['h']);
-//basic checks
-if(!$h  || strlen($h)!=64  //32*2
-        || !($file=AttachmentFile::lookup(substr($h,0,32))) //first 32 is the file hash.
-        || strcasecmp($h, $file->getDownloadHash())) //next 32 is file id + session hash.
-    Http::response(404, __('Unknown or invalid file'));
-
-if ($_GET['s'] && is_numeric($_GET['s']))
-    $file->display($_GET['s']);
-else
-    $file->display();
-?>