As you've discovered, externals *always* pull in the HEAD revision unless you specifically add a revision number to the svn:externals property. Needless to say, "rogue" svn:externals are bad for build reproducibility and tagging.
Options are: Audit the svn:externals (either manually, via a check-in hook, in the build/tagging script, etc.) in your checkedout/exported code to check for "rogue" svn:externals that are not locked down to a specific revision number. If there are "rogue" svn:externals, then you'll need to branch/tag and update the svn:externals before doing your build, or reject the code drop until the svn:externals are fixed. Another similar alternative as you've stated, is to only allow svn:externals that point to tagged code. If you want don't want to validate externals on the front end, you can try recording the externals after the fact. If you do a checkout of the code, you can cd into each external and get the revision number (via svn info.) Or you could parse the output of "svn co" or "svn export" to get the revision numbers of the externals items and record them somewhere. ("svn update" will also return the revision numbers of externals.) Ex: Create the tag, run "svn co tag", record the revision numbers pulled in, go back and add "-r 123" to the svn:externals in the tag branch. However, I haven't checked how nested externals are handled, e.g. your external reference could contain svn:externals which could have svn:externals of their own, ad infinitum. A really simple option is to export the code (including externals) and then import the code again as its own tag. Needless to say this breaks history, but it does guarantee that you can reproduce the build. Using "--ignore-externals" isn't normally practical.