diff --git a/resources/celerity/map.php b/resources/celerity/map.php
--- a/resources/celerity/map.php
+++ b/resources/celerity/map.php
@@ -9,7 +9,7 @@
   'names' => array(
     'conpherence.pkg.css' => '0e3cf785',
     'conpherence.pkg.js' => '020aebcf',
-    'core.pkg.css' => '00a2e7f4',
+    'core.pkg.css' => 'b816811e',
     'core.pkg.js' => 'd2de90d9',
     'dark-console.pkg.js' => '187792c2',
     'differential.pkg.css' => 'ffb69e3d',
@@ -147,7 +147,7 @@
     'rsrc/css/phui/phui-comment-form.css' => '68a2d99a',
     'rsrc/css/phui/phui-comment-panel.css' => 'ec4e31c0',
     'rsrc/css/phui/phui-crumbs-view.css' => '614f43cf',
-    'rsrc/css/phui/phui-curtain-object-ref-view.css' => '5f752bdb',
+    'rsrc/css/phui/phui-curtain-object-ref-view.css' => '51d93266',
     'rsrc/css/phui/phui-curtain-view.css' => '68c5efb6',
     'rsrc/css/phui/phui-document-pro.css' => 'b9613a10',
     'rsrc/css/phui/phui-document-summary.css' => 'b068eed1',
@@ -838,7 +838,7 @@
     'phui-comment-form-css' => '68a2d99a',
     'phui-comment-panel-css' => 'ec4e31c0',
     'phui-crumbs-view-css' => '614f43cf',
-    'phui-curtain-object-ref-view-css' => '5f752bdb',
+    'phui-curtain-object-ref-view-css' => '51d93266',
     'phui-curtain-view-css' => '68c5efb6',
     'phui-document-summary-view-css' => 'b068eed1',
     'phui-document-view-css' => '52b748a5',
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -3508,6 +3508,7 @@
     'PhabricatorFileTransformController' => 'applications/files/controller/PhabricatorFileTransformController.php',
     'PhabricatorFileTransformListController' => 'applications/files/controller/PhabricatorFileTransformListController.php',
     'PhabricatorFileTransformTestCase' => 'applications/files/transform/__tests__/PhabricatorFileTransformTestCase.php',
+    'PhabricatorFileUICurtainAttachController' => 'applications/files/controller/PhabricatorFileUICurtainAttachController.php',
     'PhabricatorFileUICurtainListController' => 'applications/files/controller/PhabricatorFileUICurtainListController.php',
     'PhabricatorFileUploadController' => 'applications/files/controller/PhabricatorFileUploadController.php',
     'PhabricatorFileUploadDialogController' => 'applications/files/controller/PhabricatorFileUploadDialogController.php',
@@ -9972,6 +9973,7 @@
     'PhabricatorFileTransformController' => 'PhabricatorFileController',
     'PhabricatorFileTransformListController' => 'PhabricatorFileController',
     'PhabricatorFileTransformTestCase' => 'PhabricatorTestCase',
+    'PhabricatorFileUICurtainAttachController' => 'PhabricatorFileController',
     'PhabricatorFileUICurtainListController' => 'PhabricatorFileController',
     'PhabricatorFileUploadController' => 'PhabricatorFileController',
     'PhabricatorFileUploadDialogController' => 'PhabricatorFileController',
diff --git a/src/applications/base/controller/PhabricatorController.php b/src/applications/base/controller/PhabricatorController.php
--- a/src/applications/base/controller/PhabricatorController.php
+++ b/src/applications/base/controller/PhabricatorController.php
@@ -420,6 +420,10 @@
       ->setSubmitURI($submit_uri);
   }
 
+  public function newRedirect() {
+    return id(new AphrontRedirectResponse());
+  }
+
   public function newPage() {
     $page = id(new PhabricatorStandardPageView())
       ->setRequest($this->getRequest())
diff --git a/src/applications/files/application/PhabricatorFilesApplication.php b/src/applications/files/application/PhabricatorFilesApplication.php
--- a/src/applications/files/application/PhabricatorFilesApplication.php
+++ b/src/applications/files/application/PhabricatorFilesApplication.php
@@ -95,8 +95,14 @@
         ),
         'document/(?P<engineKey>[^/]+)/(?P<phid>[^/]+)/'
           => 'PhabricatorFileDocumentController',
-        'ui/curtainlist/(?P<phid>[^/]+)/'
-          => 'PhabricatorFileUICurtainListController',
+        'ui/' => array(
+          'curtain/' => array(
+            'list/(?P<phid>[^/]+)/'
+              => 'PhabricatorFileUICurtainListController',
+            'attach/(?P<objectPHID>[^/]+)/(?P<filePHID>[^/]+)/'
+              => 'PhabricatorFileUICurtainAttachController',
+          ),
+        ),
       ) + $this->getResourceSubroutes(),
     );
   }
diff --git a/src/applications/files/controller/PhabricatorFileUICurtainAttachController.php b/src/applications/files/controller/PhabricatorFileUICurtainAttachController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/files/controller/PhabricatorFileUICurtainAttachController.php
@@ -0,0 +1,136 @@
+<?php
+
+final class PhabricatorFileUICurtainAttachController
+  extends PhabricatorFileController {
+
+  public function handleRequest(AphrontRequest $request) {
+    $viewer = $request->getViewer();
+
+    $object_phid = $request->getURIData('objectPHID');
+    $file_phid = $request->getURIData('filePHID');
+
+    $object = id(new PhabricatorObjectQuery())
+      ->setViewer($viewer)
+      ->withPHIDs(array($object_phid))
+      ->executeOne();
+    if (!$object) {
+      return new Aphront404Response();
+    }
+
+    $attachment = id(new PhabricatorFileAttachmentQuery())
+      ->setViewer($viewer)
+      ->withObjectPHIDs(array($object->getPHID()))
+      ->withFilePHIDs(array($file_phid))
+      ->needFiles(true)
+      ->withVisibleFiles(true)
+      ->executeOne();
+    if (!$attachment) {
+      return new Aphront404Response();
+    }
+
+    $file = $attachment->getFile();
+    $file_phid = $file->getPHID();
+
+    $handles = $viewer->loadHandles(
+      array(
+        $object_phid,
+        $file_phid,
+      ));
+
+    $object_handle = $handles[$object_phid];
+    $file_handle = $handles[$file_phid];
+    $cancel_uri = $object_handle->getURI();
+
+    $dialog = $this->newDialog()
+      ->setViewer($viewer)
+      ->setTitle(pht('Attach File'))
+      ->addCancelButton($object_handle->getURI(), pht('Close'));
+
+    $file_link = phutil_tag('strong', array(), $file_handle->renderLink());
+    $object_link = phutil_tag('strong', array(), $object_handle->renderLink());
+
+    if ($attachment->isPolicyAttachment()) {
+      $body = pht(
+        'The file %s is already attached to the object %s.',
+        $file_link,
+        $object_link);
+
+      return $dialog->appendParagraph($body);
+    }
+
+    if (!$request->isDialogFormPost()) {
+      $dialog->appendRemarkup(
+        pht(
+          '(WARNING) This file is referenced by this object, but '.
+          'not formally attached to it. Users who can see the object may '.
+          'not be able to see the file.'));
+
+      $dialog->appendParagraph(
+        pht(
+          'Do you want to attach the file %s to the object %s?',
+          $file_link,
+          $object_link));
+
+      $dialog->addSubmitButton(pht('Attach File'));
+
+      return $dialog;
+    }
+
+    if (!$request->getBool('confirm')) {
+      $dialog->setTitle(pht('Confirm File Attachment'));
+
+      $dialog->addHiddenInput('confirm', 1);
+
+      $dialog->appendRemarkup(
+        pht(
+          '(IMPORTANT) If you attach this file to this object, any user who '.
+          'has permission to view the object will be able to view and '.
+          'download the file!'));
+
+      $dialog->appendParagraph(
+        pht(
+          'Really attach the file %s to the object %s, allowing any user '.
+          'who can view the object to view and download the file?',
+          $file_link,
+          $object_link));
+
+      $dialog->addSubmitButton(pht('Grant Permission'));
+
+      return $dialog;
+    }
+
+    if (!($object instanceof PhabricatorApplicationTransactionInterface)) {
+      $dialog->appendParagraph(
+        pht(
+          'This object (of class "%s") does not implement the required '.
+          'interface ("%s"), so files can not be manually attached to it.',
+          get_class($object),
+          'PhabricatorApplicationTransactionInterface'));
+
+      return $dialog;
+    }
+
+    $editor = $object->getApplicationTransactionEditor()
+      ->setActor($viewer)
+      ->setContentSourceFromRequest($request)
+      ->setContinueOnNoEffect(true)
+      ->setContinueOnMissingFields(true);
+
+    $template = $object->getApplicationTransactionTemplate();
+
+    $xactions = array();
+
+    $xactions[] = id(clone $template)
+      ->setTransactionType(PhabricatorTransactions::TYPE_FILE)
+      ->setNewValue(
+        array(
+          $file_phid => PhabricatorFileAttachment::MODE_ATTACH,
+        ));
+
+    $editor->applyTransactions($object, $xactions);
+
+    return $this->newRedirect()
+      ->setURI($cancel_uri);
+  }
+
+}
diff --git a/src/applications/files/controller/PhabricatorFileUICurtainListController.php b/src/applications/files/controller/PhabricatorFileUICurtainListController.php
--- a/src/applications/files/controller/PhabricatorFileUICurtainListController.php
+++ b/src/applications/files/controller/PhabricatorFileUICurtainListController.php
@@ -53,7 +53,7 @@
     return $this->newDialog()
       ->setViewer($viewer)
       ->setWidth(AphrontDialogView::WIDTH_FORM)
-      ->setTitle(pht('Attached Files'))
+      ->setTitle(pht('Referenced Files'))
       ->setObjectList($list)
       ->addCancelButton($object_handle->getURI(), pht('Close'));
   }
diff --git a/src/applications/files/engineextension/PhabricatorFilesCurtainExtension.php b/src/applications/files/engineextension/PhabricatorFilesCurtainExtension.php
--- a/src/applications/files/engineextension/PhabricatorFilesCurtainExtension.php
+++ b/src/applications/files/engineextension/PhabricatorFilesCurtainExtension.php
@@ -34,15 +34,16 @@
 
     $handles = $viewer->loadHandles($visible_phids);
 
-    PhabricatorPolicyFilterSet::loadHandleViewCapabilities(
-      $viewer,
-      $handles,
-      array($object));
-
     $ref_list = id(new PHUICurtainObjectRefListView())
       ->setViewer($viewer)
       ->setEmptyMessage(pht('None'));
 
+    $view_capability = PhabricatorPolicyCapability::CAN_VIEW;
+    $object_policies = PhabricatorPolicyQuery::loadPolicies(
+      $viewer,
+      $object);
+    $object_policy = idx($object_policies, $view_capability);
+
     foreach ($visible_attachments as $attachment) {
       $file_phid = $attachment->getFilePHID();
       $handle = $handles[$file_phid];
@@ -50,9 +51,38 @@
       $ref = $ref_list->newObjectRefView()
         ->setHandle($handle);
 
-      if ($handle->hasCapabilities()) {
-        if (!$handle->hasViewCapability($object)) {
-          $ref->setExiled(true);
+      $file = $attachment->getFile();
+      if (!$file) {
+        // ...
+      } else {
+        if (!$attachment->isPolicyAttachment()) {
+          $file_policies = PhabricatorPolicyQuery::loadPolicies(
+            $viewer,
+            $file);
+          $file_policy = idx($file_policies, $view_capability);
+
+          if ($object_policy->isStrongerThanOrEqualTo($file_policy)) {
+            // The file is not attached to the object, but the file policy
+            // allows anyone who can see the object to see the file too, so
+            // there is no material problem with the file not being attached.
+          } else {
+            $attach_uri = urisprintf(
+              '/file/ui/curtain/attach/%s/%s/',
+              $object->getPHID(),
+              $file->getPHID());
+
+            $attached_link = javelin_tag(
+              'a',
+              array(
+                'href' => $attach_uri,
+                'sigil' => 'workflow',
+              ),
+              pht('File Not Attached'));
+
+            $ref->setExiled(
+              true,
+              $attached_link);
+          }
         }
       }
 
@@ -63,7 +93,7 @@
     $show_all = (count($visible_attachments) < count($attachments));
     if ($show_all) {
       $view_all_uri = urisprintf(
-        '/file/ui/curtainlist/%s/',
+        '/file/ui/curtain/list/%s/',
         $object->getPHID());
 
       $loaded_count = count($attachments);
@@ -80,7 +110,7 @@
     }
 
     return $this->newPanel()
-      ->setHeaderText(pht('Attached Files'))
+      ->setHeaderText(pht('Referenced Files'))
       ->setOrder(15000)
       ->appendChild($ref_list);
   }
diff --git a/src/applications/files/phid/PhabricatorFileFilePHIDType.php b/src/applications/files/phid/PhabricatorFileFilePHIDType.php
--- a/src/applications/files/phid/PhabricatorFileFilePHIDType.php
+++ b/src/applications/files/phid/PhabricatorFileFilePHIDType.php
@@ -39,6 +39,9 @@
       $handle->setName("F{$id}");
       $handle->setFullName("F{$id}: {$name}");
       $handle->setURI($uri);
+
+      $icon = FileTypeIcon::getFileIcon($name);
+      $handle->setIcon($icon);
     }
   }
 
diff --git a/src/applications/files/query/PhabricatorFileAttachmentQuery.php b/src/applications/files/query/PhabricatorFileAttachmentQuery.php
--- a/src/applications/files/query/PhabricatorFileAttachmentQuery.php
+++ b/src/applications/files/query/PhabricatorFileAttachmentQuery.php
@@ -4,13 +4,25 @@
   extends PhabricatorCursorPagedPolicyAwareQuery {
 
   private $objectPHIDs;
+  private $filePHIDs;
   private $needFiles;
+  private $visibleFiles;
 
   public function withObjectPHIDs(array $object_phids) {
     $this->objectPHIDs = $object_phids;
     return $this;
   }
 
+  public function withFilePHIDs(array $file_phids) {
+    $this->filePHIDs = $file_phids;
+    return $this;
+  }
+
+  public function withVisibleFiles($visible_files) {
+    $this->visibleFiles = $visible_files;
+    return $this;
+  }
+
   public function needFiles($need) {
     $this->needFiles = $need;
     return $this;
@@ -34,6 +46,13 @@
         $this->objectPHIDs);
     }
 
+    if ($this->filePHIDs !== null) {
+      $where[] = qsprintf(
+        $conn,
+        'attachments.filePHID IN (%Ls)',
+        $this->filePHIDs);
+    }
+
     return $where;
   }
 
@@ -92,6 +111,12 @@
         $file_phid = $attachment->getFilePHID();
         $file = idx($files, $file_phid);
 
+        if ($this->visibleFiles && !$file) {
+          $this->didRejectResult($attachment);
+          unset($attachments[$key]);
+          continue;
+        }
+
         $attachment->attachFile($file);
       }
     }
diff --git a/src/applications/files/storage/PhabricatorFileAttachment.php b/src/applications/files/storage/PhabricatorFileAttachment.php
--- a/src/applications/files/storage/PhabricatorFileAttachment.php
+++ b/src/applications/files/storage/PhabricatorFileAttachment.php
@@ -46,6 +46,15 @@
     );
   }
 
+  public function isPolicyAttachment() {
+    switch ($this->getAttachmentMode()) {
+      case self::MODE_ATTACH:
+        return true;
+      default:
+        return false;
+    }
+  }
+
   public function attachObject($object) {
     $this->object = $object;
     return $this;
diff --git a/src/applications/policy/storage/PhabricatorPolicy.php b/src/applications/policy/storage/PhabricatorPolicy.php
--- a/src/applications/policy/storage/PhabricatorPolicy.php
+++ b/src/applications/policy/storage/PhabricatorPolicy.php
@@ -417,12 +417,23 @@
       PhabricatorPolicies::POLICY_NOONE => 1,
     );
 
-    $this_strength = idx($strengths, $this->getPHID(), 0);
-    $other_strength = idx($strengths, $other->getPHID(), 0);
+    $this_strength = idx($strengths, $this_policy, 0);
+    $other_strength = idx($strengths, $other_policy, 0);
 
     return ($this_strength > $other_strength);
   }
 
+  public function isStrongerThanOrEqualTo(PhabricatorPolicy $other) {
+    $this_policy = $this->getPHID();
+    $other_policy = $other->getPHID();
+
+    if ($this_policy === $other_policy) {
+      return true;
+    }
+
+    return $this->isStrongerThan($other);
+  }
+
   public function isValidPolicyForEdit() {
     return $this->getType() !== PhabricatorPolicyType::TYPE_MASKED;
   }
diff --git a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php
--- a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php
+++ b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php
@@ -2321,6 +2321,7 @@
 
     $xaction = $object->getApplicationTransactionTemplate()
       ->setTransactionType(PhabricatorTransactions::TYPE_FILE)
+      ->setMetadataValue('attach.implicit', true)
       ->setNewValue($new_map);
 
     return $xaction;
diff --git a/src/applications/transactions/storage/PhabricatorApplicationTransaction.php b/src/applications/transactions/storage/PhabricatorApplicationTransaction.php
--- a/src/applications/transactions/storage/PhabricatorApplicationTransaction.php
+++ b/src/applications/transactions/storage/PhabricatorApplicationTransaction.php
@@ -341,6 +341,9 @@
         $phids[] = $old;
         $phids[] = $new;
         break;
+      case PhabricatorTransactions::TYPE_FILE:
+        $phids[] = array_keys($old + $new);
+        break;
       case PhabricatorTransactions::TYPE_EDGE:
         $record = PhabricatorEdgeChangeRecord::newFromTransaction($this);
         $phids[] = $record->getChangedPHIDs();
@@ -592,7 +595,9 @@
 
     // Always hide file attach/detach transactions.
     if ($xaction_type === PhabricatorTransactions::TYPE_FILE) {
-      return true;
+      if ($this->getMetadataValue('attach.implicit')) {
+        return true;
+      }
     }
 
     // Hide creation transactions if the old value is empty. These are
@@ -1041,6 +1046,124 @@
             '%s updated subscribers...',
             $this->renderHandleLink($author_phid));
         }
+        break;
+      case PhabricatorTransactions::TYPE_FILE:
+        $add = array_diff_key($new, $old);
+        $add = array_keys($add);
+
+        $rem = array_diff_key($old, $new);
+        $rem = array_keys($rem);
+
+        $mod = array();
+        foreach ($old + $new as $key => $ignored) {
+          if (!isset($old[$key])) {
+            continue;
+          }
+
+          if (!isset($new[$key])) {
+            continue;
+          }
+
+          if ($old[$key] === $new[$key]) {
+            continue;
+          }
+
+          $mod[] = $key;
+        }
+
+        // Specialize the specific case of only modifying files and upgrading
+        // references to attachments. This is accessible via the UI and can
+        // be shown more clearly than the generic default transaction shows
+        // it.
+
+        $mode_reference = PhabricatorFileAttachment::MODE_REFERENCE;
+        $mode_attach = PhabricatorFileAttachment::MODE_ATTACH;
+
+        $is_refattach = false;
+        if ($mod && !$add && !$rem) {
+          $all_refattach = true;
+          foreach ($mod as $phid) {
+            if (idx($old, $phid) !== $mode_reference) {
+              $all_refattach = false;
+              break;
+            }
+            if (idx($new, $phid) !== $mode_attach) {
+              $all_refattach = false;
+              break;
+            }
+          }
+          $is_refattach = $all_refattach;
+        }
+
+        if ($is_refattach) {
+          return pht(
+            '%s attached %s referenced file(s): %s.',
+            $this->renderHandleLink($author_phid),
+            phutil_count($mod),
+            $this->renderHandleList($mod));
+        } else if ($add && $rem && $mod) {
+          return pht(
+            '%s updated %s attached file(s), added %s: %s; removed %s: %s; '.
+            'modified %s: %s.',
+            $this->renderHandleLink($author_phid),
+            new PhutilNumber(count($add) + count($rem)),
+            phutil_count($add),
+            $this->renderHandleList($add),
+            phutil_count($rem),
+            $this->renderHandleList($rem),
+            phutil_count($mod),
+            $this->renderHandleList($mod));
+        } else if ($add && $rem) {
+          return pht(
+            '%s updated %s attached file(s), added %s: %s; removed %s: %s.',
+            $this->renderHandleLink($author_phid),
+            new PhutilNumber(count($add) + count($rem)),
+            phutil_count($add),
+            $this->renderHandleList($add),
+            phutil_count($rem),
+            $this->renderHandleList($rem));
+        } else if ($add && $mod) {
+          return pht(
+            '%s updated %s attached file(s), added %s: %s; modified %s: %s.',
+            $this->renderHandleLink($author_phid),
+            new PhutilNumber(count($add) + count($mod)),
+            phutil_count($add),
+            $this->renderHandleList($add),
+            phutil_count($mod),
+            $this->renderHandleList($mod));
+        } else if ($rem && $mod) {
+          return pht(
+            '%s updated %s attached file(s), removed %s: %s; modified %s: %s.',
+            $this->renderHandleLink($author_phid),
+            new PhutilNumber(count($rem) + count($mod)),
+            phutil_count($rem),
+            $this->renderHandleList($rem),
+            phutil_count($mod),
+            $this->renderHandleList($mod));
+        } else if ($add) {
+          return pht(
+            '%s attached %s file(s): %s.',
+            $this->renderHandleLink($author_phid),
+            phutil_count($add),
+            $this->renderHandleList($add));
+        } else if ($rem) {
+          return pht(
+            '%s removed %s attached file(s): %s.',
+            $this->renderHandleLink($author_phid),
+            phutil_count($rem),
+            $this->renderHandleList($rem));
+        } else if ($mod) {
+          return pht(
+            '%s modified %s attached file(s): %s.',
+            $this->renderHandleLink($author_phid),
+            phutil_count($mod),
+            $this->renderHandleList($mod));
+        } else {
+          return pht(
+            '%s attached files...',
+            $this->renderHandleLink($author_phid));
+        }
+
         break;
       case PhabricatorTransactions::TYPE_EDGE:
         $record = PhabricatorEdgeChangeRecord::newFromTransaction($this);
@@ -1479,6 +1602,8 @@
 
   public function hasChangeDetails() {
     switch ($this->getTransactionType()) {
+      case PhabricatorTransactions::TYPE_FILE:
+        return true;
       case PhabricatorTransactions::TYPE_CUSTOMFIELD:
         $field = $this->getTransactionCustomField();
         if ($field) {
@@ -1494,6 +1619,11 @@
   }
 
   public function renderChangeDetailsForMail(PhabricatorUser $viewer) {
+    switch ($this->getTransactionType()) {
+      case PhabricatorTransactions::TYPE_FILE:
+        return false;
+    }
+
     $view = $this->renderChangeDetails($viewer);
     if ($view instanceof PhabricatorApplicationTransactionTextDiffDetailView) {
       return $view->renderForMail();
@@ -1503,6 +1633,8 @@
 
   public function renderChangeDetails(PhabricatorUser $viewer) {
     switch ($this->getTransactionType()) {
+      case PhabricatorTransactions::TYPE_FILE:
+        return $this->newFileTransactionChangeDetails($viewer);
       case PhabricatorTransactions::TYPE_CUSTOMFIELD:
         $field = $this->getTransactionCustomField();
         if ($field) {
@@ -1769,6 +1901,66 @@
       ->addInt(-$this->getActionStrength());
   }
 
+  private function newFileTransactionChangeDetails(PhabricatorUser $viewer) {
+    $old = $this->getOldValue();
+    $new = $this->getNewValue();
+
+    $phids = array_keys($old + $new);
+    $handles = $viewer->loadHandles($phids);
+
+    $names = array(
+      PhabricatorFileAttachment::MODE_REFERENCE => pht('Referenced'),
+      PhabricatorFileAttachment::MODE_ATTACH => pht('Attached'),
+    );
+
+    $rows = array();
+    foreach ($old + $new as $phid => $ignored) {
+      $handle = $handles[$phid];
+
+      $old_mode = idx($old, $phid);
+      $new_mode = idx($new, $phid);
+
+      if ($old_mode === null) {
+        $old_name = pht('None');
+      } else if (isset($names[$old_mode])) {
+        $old_name = $names[$old_mode];
+      } else {
+        $old_name = pht('Unknown ("%s")', $old_mode);
+      }
+
+      if ($new_mode === null) {
+        $new_name = pht('Detached');
+      } else if (isset($names[$new_mode])) {
+        $new_name = $names[$new_mode];
+      } else {
+        $new_name = pht('Unknown ("%s")', $new_mode);
+      }
+
+      $rows[] = array(
+        $handle->renderLink(),
+        $old_name,
+        $new_name,
+      );
+    }
+
+    $table = id(new AphrontTableView($rows))
+      ->setHeaders(
+        array(
+          pht('File'),
+          pht('Old Mode'),
+          pht('New Mode'),
+        ))
+      ->setColumnClasses(
+        array(
+          'pri',
+        ));
+
+    return id(new PHUIBoxView())
+      ->addMargin(PHUI::MARGIN_SMALL)
+      ->appendChild($table);
+  }
+
+
 
 /* -(  PhabricatorPolicyInterface Implementation  )-------------------------- */
 
@@ -1836,5 +2028,4 @@
     $this->saveTransaction();
   }
 
-
 }
diff --git a/src/infrastructure/internationalization/translation/PhabricatorUSEnglishTranslation.php b/src/infrastructure/internationalization/translation/PhabricatorUSEnglishTranslation.php
--- a/src/infrastructure/internationalization/translation/PhabricatorUSEnglishTranslation.php
+++ b/src/infrastructure/internationalization/translation/PhabricatorUSEnglishTranslation.php
@@ -1789,6 +1789,20 @@
         'Executed %s tasks.',
       ),
 
+      '%s modified %s attached file(s): %s.' => array(
+        array(
+          '%s modified an attached file: %3$s.',
+          '%s modified attached files: %3$s.',
+        ),
+      ),
+
+      '%s attached %s referenced file(s): %s.' => array(
+        array(
+          '%s attached a referenced file: %3$s.',
+          '%s attached referenced files: %3$s.',
+        ),
+      ),
+
     );
   }
 
diff --git a/src/view/phui/PHUICurtainObjectRefView.php b/src/view/phui/PHUICurtainObjectRefView.php
--- a/src/view/phui/PHUICurtainObjectRefView.php
+++ b/src/view/phui/PHUICurtainObjectRefView.php
@@ -7,6 +7,7 @@
   private $epoch;
   private $highlighted;
   private $exiled;
+  private $exileNote = false;
 
   public function setHandle(PhabricatorObjectHandle $handle) {
     $this->handle = $handle;
@@ -23,8 +24,9 @@
     return $this;
   }
 
-  public function setExiled($is_exiled) {
+  public function setExiled($is_exiled, $note = false) {
     $this->exiled = $is_exiled;
+    $this->exileNote = $note;
     return $this;
   }
 
@@ -72,10 +74,16 @@
     }
 
     if ($this->exiled) {
+      if ($this->exileNote !== false) {
+        $exile_note = $this->exileNote;
+      } else {
+        $exile_note = pht('No View Permission');
+      }
+
       $exiled_view = array(
         id(new PHUIIconView())->setIcon('fa-eye-slash red'),
         ' ',
-        pht('No View Permission'),
+        $exile_note,
       );
 
       $exiled_cells = array();
diff --git a/webroot/rsrc/css/phui/phui-curtain-object-ref-view.css b/webroot/rsrc/css/phui/phui-curtain-object-ref-view.css
--- a/webroot/rsrc/css/phui/phui-curtain-object-ref-view.css
+++ b/webroot/rsrc/css/phui/phui-curtain-object-ref-view.css
@@ -92,6 +92,7 @@
   opacity: 0.75;
 }
 
-.phui-curtain-object-ref-view-exiled-cell {
+.phui-curtain-object-ref-view-exiled-cell,
+.phui-curtain-object-ref-view-exiled-cell a {
   color: {$red};
 }