add CSRF prevention token requirements to most article modification
authorTony Cook <tony@develop-help.com>
Wed, 24 Mar 2010 03:59:11 +0000 (03:59 +0000)
committertony <tony@45cb6cf1-00bc-42d2-bb5a-07f51df49f94>
Wed, 24 Mar 2010 03:59:11 +0000 (03:59 +0000)
actions

WARNING: You MUST update your templates to include the tokens or they
functions your links and forms perform won't work.

don't double encode & in file move urls

site/cgi-bin/modules/BSE/Edit/Article.pm
site/templates/admin/article_img.tmpl
site/templates/admin/edit_0.tmpl
site/templates/admin/edit_1.tmpl
site/templates/admin/edit_steps.tmpl
site/templates/admin/file_edit.tmpl
site/templates/admin/filelist.tmpl
site/templates/admin/image_edit.tmpl

index 946c33c..54d66d9 100644 (file)
@@ -838,13 +838,16 @@ sub tag_imgmove {
   $url .= $urladd;
 
   my $image = $images->[$$rindex];
-  my $down_url;
+  my $csrfp = $req->get_csrf_token("admin_move_image");
+  my $baseurl = "$ENV{SCRIPT_NAME}?id=$article->{id}&imageid=$image->{id}&";
+  $baseurl .= "_csrfp=$csrfp&";
+  my $down_url = "";
   if ($$rindex < $#$images) {
-    $down_url = "$ENV{SCRIPT_NAME}?id=$article->{id}&moveimgdown=1&imageid=$image->{id}";
+    $down_url = $baseurl . "moveimgdown=1";
   }
-  my $up_url = '';
+  my $up_url = "";
   if ($$rindex > 0) {
-    $up_url = "$ENV{SCRIPT_NAME}?id=$article->{id}&moveimgup=1&imageid=$image->{id}";
+    $up_url = $baseurl . "moveimgup=1";
   }
   return make_arrows($req->cfg, $down_url, $up_url, $url, $img_prefix);
 }
@@ -873,12 +876,15 @@ sub tag_movefiles {
   }
 
   my $down_url = "";
+  my $csrfp = $req->get_csrf_token("admin_move_file");
+  my $baseurl = "$ENV{SCRIPT_NAME}?fileswap=1&id=$article->{id}&";
+  $baseurl .= "_csrfp=$csrfp&";
   if ($$rindex < $#$files) {
-    $down_url = "$ENV{SCRIPT_NAME}?fileswap=1&amp;id=$article->{id}&amp;file1=$files->[$$rindex]{id}&amp;file2=$files->[$$rindex+1]{id}";
+    $down_url = $baseurl . "file1=$files->[$$rindex]{id}&file2=$files->[$$rindex+1]{id}";
   }
   my $up_url = "";
   if ($$rindex > 0) {
-    $up_url = "$ENV{SCRIPT_NAME}?fileswap=1&amp;id=$article->{id}&amp;file1=$files->[$$rindex]{id}&amp;file2=$files->[$$rindex-1]{id}";
+    $up_url = $baseurl . "file1=$files->[$$rindex]{id}&file2=$files->[$$rindex-1]{id}";
   }
 
   return make_arrows($req->cfg, $down_url, $up_url, $url, $img_prefix);
@@ -1309,8 +1315,8 @@ sub edit_form {
   return $self->low_edit_form($request, $article, $articles, $msg, $errors);
 }
 
-sub add_form {
-  my ($self, $req, $articles, $msg, $errors) = @_;
+sub _dummy_article {
+  my ($self, $req, $articles, $rmsg) = @_;
 
   my $level;
   my $cgi = $req->cgi;
@@ -1347,13 +1353,25 @@ sub add_form {
 
   my ($values, $labels) = $self->possible_parents(\%article, $articles, $req);
   unless (@$values) {
+    $$rmsg = "You can't add children to any article at that level";
+    return;
+  }
+
+  return \%article;
+}
+
+sub add_form {
+  my ($self, $req, $articles, $msg, $errors) = @_;
+
+  my $mymsg;
+  my $article = $self->_dummy_article($req, $articles, \$mymsg);
+  unless ($article) {
     require BSE::Edit::Site;
     my $site = BSE::Edit::Site->new(cfg=>$req->cfg, db=> BSE::DB->single);
-    return $site->edit_sections($req, $articles, 
-                               "You can't add children to any article at that level");
+    return $site->edit_sections($req, $articles, $mymsg);
   }
 
-  return $self->low_edit_form($req, \%article, $articles, $msg, $errors);
+  return $self->low_edit_form($req, $article, $articles, $msg, $errors);
 }
 
 sub generator { 'Generate::Article' }
@@ -1488,6 +1506,9 @@ sub make_link {
 
 sub save_new {
   my ($self, $req, $articles) = @_;
+
+  $req->check_csrf("admin_add_article")
+    or return $self->csrf_error($req, undef, "admin_add_article", "Add Article");
   
   my $cgi = $req->cgi;
   my %data;
@@ -1639,6 +1660,9 @@ sub fill_old_data {
 sub save {
   my ($self, $req, $article, $articles) = @_;
 
+  $req->check_csrf("admin_save_article")
+    or return $self->csrf_error($req, $article, "admin_save_article", "Save Article");
+
   $req->user_can(edit_save => $article)
     or return $self->edit_form($req, $article, $articles,
                               "You don't have access to save this article");
@@ -1991,6 +2015,9 @@ sub child_types {
 sub add_stepkid {
   my ($self, $req, $article, $articles) = @_;
 
+  $req->check_csrf("admin_add_stepkid")
+    or return $self->csrf_error($req, $article, "admin_add_stepkid", "Add Stepkid");
+
   $req->user_can(edit_stepkid_add => $article)
     or return $self->edit_form($req, $article, $articles,
                               "You don't have access to add step children to this article");
@@ -2031,6 +2058,8 @@ sub add_stepkid {
 sub del_stepkid {
   my ($self, $req, $article, $articles) = @_;
 
+  $req->check_csrf("admin_remove_stepkid")
+    or return $self->csrf_error($req, $article, "admin_del_stepkid", "Delete Stepkid");
   $req->user_can(edit_stepkid_delete => $article)
     or return $self->edit_form($req, $article, $articles,
                               "You don't have access to delete stepchildren from this article");
@@ -2064,6 +2093,9 @@ sub del_stepkid {
 sub save_stepkids {
   my ($self, $req, $article, $articles) = @_;
 
+  $req->check_csrf("admin_save_stepkids")
+    or return $self->csrf_error($req, $article, "admin_save_stepkids", "Save Stepkids");
+
   $req->user_can(edit_stepkid_save => $article)
     or return $self->edit_form($req, $article, $articles,
                               "No access to save stepkid data for this article");
@@ -2106,6 +2138,9 @@ sub save_stepkids {
 sub add_stepparent {
   my ($self, $req, $article, $articles) = @_;
 
+  $req->check_csrf("admin_add_stepparent")
+    or return $self->csrf_error($req, $article, "admin_add_stepparent", "Add Stepparent");
+
   $req->user_can(edit_stepparent_add => $article)
     or return $self->edit_form($req, $article, $articles,
                               "You don't have access to add stepparents to this article");
@@ -2150,6 +2185,9 @@ sub add_stepparent {
 sub del_stepparent {
   my ($self, $req, $article, $articles) = @_;
 
+  $req->check_csrf("admin_remove_stepparent")
+    or return $self->csrf_error($req, $article, "admin_del_stepparent", "Delete Stepparent");
+
   $req->user_can(edit_stepparent_delete => $article)
     or return $self->edit_form($req, $article, $articles,
                               "You cannot remove stepparents from that article");
@@ -2184,6 +2222,8 @@ sub del_stepparent {
 sub save_stepparents {
   my ($self, $req, $article, $articles) = @_;
 
+  $req->check_csrf("admin_save_stepparents")
+    or return $self->csrf_error($req, $article, "admin_save_stepparents", "Save Stepparents");
   $req->user_can(edit_stepparent_save => $article)
     or return $self->edit_form($req, $article, $articles,
                               "No access to save stepparent data for this artice");
@@ -2280,6 +2320,9 @@ sub show_images {
 sub save_image_changes {
   my ($self, $req, $article, $articles) = @_;
 
+  $req->check_csrf("admin_save_images")
+    or return $self->csrf_error($req, $article, "admin_save_images", "Save Images");
+
   $req->user_can(edit_images_save => $article)
     or return $self->edit_form($req, $article, $articles,
                                 "You don't have access to save image information for this article");
@@ -2684,6 +2727,8 @@ sub do_add_image {
 sub add_image {
   my ($self, $req, $article, $articles) = @_;
 
+  $req->check_csrf("admin_add_image")
+    or return $self->csrf_error($req, $article, "admin_add_image", "Add Image");
   $req->user_can(edit_images_add => $article)
     or return $self->_service_error($req, $article, $articles,
                                    "You don't have access to add new images to this article");
@@ -2738,6 +2783,9 @@ sub _image_manager {
 sub remove_img {
   my ($self, $req, $article, $articles, $imageid) = @_;
 
+  $req->check_csrf("admin_remove_image")
+    or return $self->csrf_error($req, $article, "admin_remove_image", "Remove Image");
+
   $req->user_can(edit_images_delete => $article)
     or return $self->edit_form($req, $article, $articles,
                                 "You don't have access to delete images from this article");
@@ -2766,6 +2814,8 @@ sub remove_img {
 sub move_img_up {
   my ($self, $req, $article, $articles) = @_;
 
+  $req->check_csrf("admin_move_image")
+    or return $self->csrf_error($req, $article, "admin_move_image", "Move Image");
   $req->user_can(edit_images_reorder => $article)
     or return $self->edit_form($req, $article, $articles,
                                 "You don't have access to reorder images in this article");
@@ -2791,6 +2841,8 @@ sub move_img_up {
 sub move_img_down {
   my ($self, $req, $article, $articles) = @_;
 
+  $req->check_csrf("admin_move_image")
+    or return $self->csrf_error($req, $article, "admin_move_image", "Move Image");
   $req->user_can(edit_images_reorder => $article)
     or return $self->edit_form($req, $article, $articles,
                                 "You don't have access to reorder images in this article");
@@ -2912,6 +2964,8 @@ sub req_edit_image {
 sub req_save_image {
   my ($self, $req, $article, $articles) = @_;
   
+  $req->check_csrf("admin_save_image")
+    or return $self->csrf_error($req, $article, "admin_save_image", "Save Image");
   my $cgi = $req->cgi;
 
   my $id = $cgi->param('image_id');
@@ -3093,6 +3147,8 @@ my %file_fields =
 sub fileadd {
   my ($self, $req, $article, $articles) = @_;
 
+  $req->check_csrf("admin_add_file")
+    or return $self->csrf_error($req, $article, "admin_add_file", "Add File");
   $req->user_can(edit_files_add => $article)
     or return $self->edit_form($req, $article, $articles,
                              "You don't have access to add files to this article");
@@ -3272,6 +3328,9 @@ sub fileadd {
 sub fileswap {
   my ($self, $req, $article, $articles) = @_;
 
+  $req->check_csrf("admin_move_file")
+    or return $self->csrf_error($req, $article, "admin_move_file", "Move File");
+
   $req->user_can('edit_files_reorder', $article)
     or return $self->edit_form($req, $article, $articles,
                           "You don't have access to reorder files in this article");
@@ -3303,6 +3362,8 @@ sub fileswap {
 sub filedel {
   my ($self, $req, $article, $articles) = @_;
 
+  $req->check_csrf("admin_remove_file")
+    or return $self->csrf_error($req, $article, "admin_remove_file", "Delete File");
   $req->user_can('edit_files_delete', $article)
     or return $self->edit_form($req, $article, $articles,
                               "You don't have access to delete files from this article");
@@ -3333,6 +3394,9 @@ sub filedel {
 sub filesave {
   my ($self, $req, $article, $articles) = @_;
 
+  $req->check_csrf("admin_save_files")
+    or return $self->csrf_error($req, $article, "admin_save_files", "Save Files");
+
   $req->user_can('edit_files_save', $article)
     or return $self->edit_form($req, $article, $articles,
                           "You don't have access to save file information for this article");
@@ -3715,6 +3779,9 @@ sub req_edit_file {
 sub req_save_file {
   my ($self, $req, $article, $articles) = @_;
 
+  $req->check_csrf("admin_save_file")
+    or return $self->csrf_error($req, $article, "admin_save_file", "Save File");
+
   my $cgi = $req->cgi;
 
   my @files = $self->get_files($article);
@@ -3967,6 +4034,9 @@ sub can_remove {
 sub remove {
   my ($self, $req, $article, $articles) = @_;
 
+  $req->check_csrf("admin_remove_article")
+    or return $self->csrf_error($req, $article, "admin_remove_article", "Remove Article");
+
   my $why_not;
   unless ($self->can_remove($req, $article, $articles, \$why_not)) {
     return $self->edit_form($req, $article, $articles, $why_not);
@@ -4297,6 +4367,13 @@ sub csrf_error {
   my %errors;
   my $msg = $req->csrf_error;
   $errors{_csrfp} = $msg;
+  my $mymsg;
+  $article ||= $self->_dummy_article($req, 'Articles', \$mymsg);
+  unless ($article) {
+    require BSE::Edit::Site;
+    my $site = BSE::Edit::Site->new(cfg=>$req->cfg, db=> BSE::DB->single);
+    return $site->edit_sections($req, 'Articles', $mymsg);
+  }
   return $self->_service_error($req, $article, 'Articles', $msg, \%errors);
 }
 
index 45e4ebc..16e268e 100644 (file)
@@ -25,6 +25,7 @@
 <input type="hidden" name="parentid" value="<: article parentid :>" />
 <input type="hidden" name="imgtype" value="<: articleType :>" />
 <input type="hidden" name="_t" value="img" />
+<:csrfp admin_add_image hidden:>
   <table border="0" cellspacing="0" cellpadding="0" bgcolor="#000000" class="table">
     <tr> 
       <td> 
@@ -87,6 +88,7 @@
 <input type="hidden" name="parentid" value="<: article parentid :>" />
 <input type="hidden" name="imgtype" value="<: articleType :>" />
 <input type="hidden" name="_t" value="img" />
+<:csrfp admin_save_images hidden:>
   <h2>Manage images</h2>
 
 <table width="100%" border="0" cellpadding="0" cellspacing="0" bgcolor="#000000" class="table">
               <:ifUserCan edit_images_save:article:><input type="text" name="alt<:image id:>" value="<: oldi [concatenate alt [image id] ] 0 image alt :>" size="32" /><:or:><: image alt :><:eif:>
             </td>
             <td valign="top" nowrap="nowrap" rowspan="5" bgcolor="#FFFFFF"> 
-              <:ifUserCan edit_images_delete:article:><b><a href="<:script:>?id=<:article id:>&removeimg_<: image id :>=1&_t=img" onClick="return window.confirm('Are you sure you want to delete this Image')">Delete</a></b><:or:><:eif:>
+              <:ifUserCan edit_images_delete:article:><b><a href="<:script:>?id=<:article id:>&amp;removeimg_<: image id :>=1&amp;_t=img&amp;_csrfp=<:csrfp admin_remove_image:>" onClick="return window.confirm('Are you sure you want to delete this Image')">Delete</a></b><:or:><:eif:>
 <:ifUserCan edit_images_save:article:><a href="<:script:>?a_edit_image=1&amp;id=<:article id:>&image_id=<: image id :>">Edit</a><:or:><:eif:></td>
             <td nowrap="nowrap" bgcolor="#FFFFFF" rowspan="5"><:imgmove:></td>
          </tr>
               <:ifUserCan edit_images_save:article:><input type="text" name="name<:image id:>" value="<: oldi [concatenate name [image id] ] 0 image name :>" size="32" /> <:error_img [concatenate "name" [image id] ]:><:or:><: image name :><:eif:>
             </td>
             <td valign="bottom" nowrap="nowrap"> 
-              <:ifUserCan edit_images_delete:article:><b><a href="<:script:>?id=<:article id:>&removeimg_<: image id :>=1&_t=img" onClick="return window.confirm('Are you sure you want to delete this Image')">Delete</a></b><:or:><:eif:></td>
+              <:ifUserCan edit_images_delete:article:><b><a href="<:script:>?id=<:article id:>&amp;removeimg_<: image id :>=1&amp;_t=img&amp;_csrfp=<:csrfp admin_remove_image:>" onClick="return window.confirm('Are you sure you want to delete this Image')">Delete</a></b><:or:><:eif:></td>
             <td nowrap="nowrap"><:imgmove:></td>
           </tr>
           <: iterator separator images :> 
index 3eee37d..e0ea622 100644 (file)
@@ -64,7 +64,7 @@
           <td width="70%"><: summary child body :></td>
           <td bgcolor="#FFFFFF" align="center"><: is child listed :></td>
           <td nowrap="nowrap"> <a href="/cgi-bin/admin/add.pl?id=<:child id:>">Edit</a> 
-            <:if UserCan edit_delete_article:child:><a href="/cgi-bin/admin/add.pl?id=<:child id:>&amp;remove=1" onclick="return window.confirm('Are you sure you want to delete this Section')">Delete</a> <:or UserCan:><:eif UserCan:></td>
+            <:if UserCan edit_delete_article:child:><a href="/cgi-bin/admin/add.pl?id=<:child id:>&amp;remove=1&amp;_csrfp=<:csrfp admin_remove_article:>" onclick="return window.confirm('Are you sure you want to delete this Section')">Delete</a> <:or UserCan:><:eif UserCan:></td>
                   <td nowrap="nowrap"><:movechild:></td>
         </tr>
         <:iterator separator children:> <:iterator end children:> 
index 9470fe8..26fb2c2 100644 (file)
@@ -50,7 +50,7 @@
     <input type="hidden" name="type" value="Article" />
     <input type="hidden" name="level" value="<: level :>" />
     <input type="hidden" name="id" value="<: article id :>" />
-
+<:ifNew:><:csrfp admin_add_article hidden:><:or:><:csrfp admin_save_article hidden:><:eif:>
         <table class="editform">
           <tr> 
             <th>Parent:</th>
index 1822ac0..e5016f0 100644 (file)
@@ -36,6 +36,7 @@
         <form action="<:script:>" method="post">
           <input type="hidden" name="id" value="<:article id:>" />
           <input type="hidden" name="_t" value="steps" />
+         <:csrfp admin_save_stepkids hidden:>
           <:iterator begin kids:> 
           <tr bgcolor="#FFFFFF"> 
             <td align="center" nowrap="nowrap"><:kid id:></td>
@@ -46,7 +47,7 @@
             <td nowrap="nowrap"><:ifStepKid:> 
               <:if UserCan edit_stepkid_save:article,edit_stepparent_save:kid :><input type="text" name="expire_<:stepkid childId:>" value="<:date "%d/%m/%Y" stepkid expire:>" size="10" /><:or UserCan:><:date "%d/%m/%Y" stepkid expire:><:eif UserCan:>
               <:or:>&nbsp;<:eif:></td>
-            <td nowrap="nowrap"><:edit kid Edit:> <:ifStepKid:><:if UserCan edit_stepkid_delete:article,edit_stepparent_delete:kid :><a href="<:script:>?del_stepkid=1&amp;id=<:stepkid parentId:>&amp;stepkid=<:stepkid childId:>&amp;_t=steps" onClick="return window.confirm('Are you sure you want to delete this Step child')">Delete</a><:or UserCan:><:eif UserCan:><:or:><:eif:> </td>
+            <td nowrap="nowrap"><:edit kid Edit:> <:ifStepKid:><:if UserCan edit_stepkid_delete:article,edit_stepparent_delete:kid :><a href="<:script:>?del_stepkid=1&amp;id=<:stepkid parentId:>&amp;stepkid=<:stepkid childId:>&amp;_t=steps&amp;_csrfp=<:csrfp admin_remove_stepkid:>" onClick="return window.confirm('Are you sure you want to delete this Step child')">Delete</a><:or UserCan:><:eif UserCan:><:or:><:eif:> </td>
                        <td nowrap="nowrap"><:movestepkid:></td>
           </tr>
           <:iterator end kids:> 
@@ -67,6 +68,7 @@
         <form action="<:script:>" method="post">
           <input type="hidden" name="id" value="<:article id:>" />
           <input type="hidden" name="_t" value="steps" />
+         <:csrfp admin_add_stepkid hidden:>
           <tr bgcolor="#FFFFFF"> 
             <td colspan="2"><:possible_stepkids:></td>
             <td> 
         <form action="<:script:>" method="post">
           <input type="hidden" name="id" value="<:article id:>" />
          <input type="hidden" name="_t" value="steps" />
-          <:iterator begin stepparents:> 
+         <:csrfp admin_save_stepparents hidden:>
+          <:iterator begin stepparents:>
           <tr bgcolor="#FFFFFF"> 
             <td align="center" nowrap="nowrap"><a href="<:stepparent_targ admin:>"><:stepparent 
               parentId:></a></td>
               <:if UserCan edit_stepparent_save:article,edit_stepkid_save:stepparent_targ:><input type="text" name="expire_<:stepparent parentId:>" value="<:date "%d/%m/%Y" stepparent expire:>" size="10" /><:or UserCan:><:date "%d/%m/%Y" stepparent expire:><:eif UserCan:>
             </td>
             <td nowrap="nowrap"><a href="/cgi-bin/admin/add.pl?id=<:stepparent parentId:>">Edit</a> 
-              <:if UserCan edit_stepkid_delete:stepparent_targ,edit_stepparent_delete:article :><a href="<:script:>?del_stepparent=1&amp;id=<:stepparent childId:>&amp;stepparent=<:stepparent parentId:>&amp;_t=steps" onClick="return window.confirm('Are you sure you want to delete this Step parent')">Delete</a> <:or UserCan:><:eif UserCan:></td>
+              <:if UserCan edit_stepkid_delete:stepparent_targ,edit_stepparent_delete:article :><a href="<:script:>?del_stepparent=1&amp;id=<:stepparent childId:>&amp;stepparent=<:stepparent parentId:>&amp;_t=steps&amp;_csrfp=<:csrfp admin_remove_stepparent:>" onClick="return window.confirm('Are you sure you want to delete this Step parent')">Delete</a> <:or UserCan:><:eif UserCan:></td>
                          <td nowrap="nowrap"><:movestepparent:></td>
           </tr>
           <:iterator end stepparents:> 
         <form action="<:script:>" method="post">
           <input type="hidden" name="id" value="<:article id:>" />
           <input type="hidden" name="_t" value="steps" />
+         <:csrfp admin_add_stepparent hidden:>
           <tr bgcolor="#FFFFFF"> 
             <td colspan=2><:stepparent_possibles:></td>
             <td> 
index 8b9c9c2..17eb964 100644 (file)
@@ -17,6 +17,7 @@
 <input type="hidden" name="file_id" value="<:efile id:>" />
 <input type="hidden" name="_t" value="file" />
 <input type="hidden" name="save_file_flags" value="1" />
+<:csrfp admin_save_file hidden:>
         <table class="editform editformsmall" id="filelist">
           <tr> 
             <th align="left">Replacement file:</th>
index 9d1590f..e0b5534 100644 (file)
@@ -15,6 +15,7 @@
 
 <input type="hidden" name="id" value="<: article id :>" />
 <input type="hidden" name="_t" value="file" />
+<:csrfp admin_add_file hidden:>
         <table class="editform editformsmall">
           <tr> 
             <th>File to add:</th>
 <input type="hidden" name="id" value="<: article id :>" />
 <input type="hidden" name="_t" value="file" />
 <input type="hidden" name="save_file_flags" value="1" />
+<:csrfp admin_save_files hidden:>
         <table id="filelist" class="editform">
           <:if Files:><tr> 
             <th nowrap="nowrap" bgcolor="#FFFFFF"> File</th>
                     &nbsp;&nbsp;&nbsp;
                   
 <:ifUserCan edit_files_save:article:><b><a href="<:script:>?a_edit_file=1&amp;id=<:article id:>&amp;file_id=<:file id:>">Edit</a></b> <:or:><:eif:>
-<:ifUserCan edit_files_delete:article:><b><a href="<:script:>?filedel=1&amp;id=<:article id:>&amp;file=<:file id:>&amp;_t=file" onClick="return window.confirm('Are you sure you want to delete this File')">Delete</a></b> <:or:><:eif:>
+<:ifUserCan edit_files_delete:article:><b><a href="<:script:>?filedel=1&amp;id=<:article id:>&amp;file=<:file id:>&amp;_t=file&amp;_csrfp=<:csrfp admin_remove_file:>" onClick="return window.confirm('Are you sure you want to delete this File')">Delete</a></b> <:or:><:eif:>
                     <:movefiles:>
 <span class="file_info_trigger">Info
 <div class="file_info">
index 560a0e6..f1e68b2 100644 (file)
@@ -13,6 +13,7 @@
 <input type="hidden" name="id" value="<: article id :>" />
 <input type="hidden" name="image_id" value="<: eimage id :>" />
 <input type="hidden" name="r" value="/cgi-bin/admin/add.pl?id=<:article id:>&amp;_t=img" />
+<:csrfp admin_save_image hidden:>
 <table cellpadding="6" border="0" cellspacing="1">
   <tr> 
     <th align="left">Replacement image file:</th>