I can not find any documentation that specifies on which thread WebClient raises its events. I ran some tests and determined the following:
If called from a
For WebClient, I haven't found it documented either, but have seen the same behaviour as you. Essentially this can be described as "if there's an active synchronization context when the call is started, it's used - otherwise the thread pool is used."
For the async behaviour in C# 5, it depends on the implementation of whatever you're awaiting... but I believe the awaiter for Task will use TaskScheduler.Current to schedule a continuation - which means you'll see the same sort of behaviour. (It's not necessarily just a UI thread which sets a task scheduler, but that's the most obvious example.)
When thread pool threads are used, it should still be thread-safe - the method is only executing in a single thread at a time, and I believe the Task Parallel Library performs all the required memory barriers.
If you're interested in how async hangs together behind the scenes, you might want to read my Eduasync blog series.