Shotgun thoughts:

- You don't need the `Hold`/`ReleaseHold` pair; `Unevaluated` will do: `Unevaluated[f] /. rules`

- You can use direct [destructuring][1] to extract `extvar`: `curvature[f_, range : {var_, __}] :=`

- By extracting `var` as above you can `Block` it directly, simplifying everything.

- You can leave the `Table` variable out of the main `Block` as it is already localized.

- `res /. {z_} :> z` can replace the line `If[Length[res] == 1, res = res[[1]]]; res` 

- In fact `res` can be eliminated and the rule applied to the `Table`

- You can pre-evaluate your `1/Sqrt[Total[D[fn,var]^2]]` expression; this should be faster, and also eliminates the need for the replacement inside the `Table`




Putting it together I would write:

    SetAttributes[curvature, HoldAll];
    
    curvature[f_, range : {var_, __}] :=
      Block[{var, fn},
        fn = If[ListQ[f], f, {var, f}];
        fn = 1/Sqrt[Total[D[fn, var]^2]];
        Table[fn, range] /. {z_} :> z
      ]

You will notice red highlighting of `var` signifying a *possible* conflict; this is *not* a problem and is in fact exactly what I desire: the sharing of `var` between the function, the `Block`, and the `Table`.


  [1]: http://mathematica.stackexchange.com/a/8399/121