Technically, as per my test, you **do need** to escape it.
But the good side is that, `arg()` does not use the direct user input always.
If the URL (or more precisely, `$_GET['q']`) is `node/<h3>/edit`, `arg(1)` returns `<h3>` without a check plain.
If you want to test it yourself, add the snippet below and see yourself.
<?php
echo (arg(1, 'node/<h3>/edit')); ?>Normal text
You will now see "Normal text" in h3.
If a node has ID 4, when viewing the node, `$_GET['q']` would be node/4. If the path is not aliased, URL would be the same.
as per the example above, if the user opened `node/<h3>`, `arg(1)` would be `<h3>` without escaping but there is a doubt that will user sees your snippet that you used `arg()` because that page returns a 404 result (where you don't see any blocks, page content, etc).
Using `arg()` in `t()`, url() , `l()` and other functions will always escape/sanitize the result so in practical world, it's unlikely that you'll find a real case that someone can XSS your site.
Here is a bad use that I can think about.
In page.tpl.php file, you could add a class from the URL path like this:
<body class="<?php print arg(0); ?>">
You could expect that on node pages, you will see body tag's class is "node", and on admin pages, class is "admin". But imagine the user opens a page like this:
[To see links please register here]
; onclick="alert('You are clicking on me');"
So the actual HTML of the body tag would be like this:
<body class="" onclick="alert('You are clicking on me');">
Now you will see that the body tag has an empty class attribute, and the body also has an onclick event added. This could be the worst example you can see - but I just wanted to show you some real example.
Using `$node->nid` is safe though.