$.ajaxSetup is global, and that is the whole problem

$.ajaxSetup is the documented way to attach a CSRF token or an authentication header to every request, and it does exactly that — including requests made by jQuery internals, by every plugin on the page, and by code written a year from now whose author has no idea the defaults were changed.

// global: the analytics widget's requests get these too
$.ajaxSetup({
    headers:    { 'X-CSRF-Token': token },
    beforeSend: function (xhr) { spinner.show(); }
});

// and a call with its own beforeSend REPLACES the global one
$.ajax({ url: '/orders', beforeSend: function () {} });   // no spinner

// scoped instead: one function, visible at every call site
function api(options) {
    return $.ajax($.extend({
        headers: { 'X-CSRF-Token': token }
    }, options));
}

The merge is shallow and per key, so a call supplying its own beforeSend, headers or error discards the global value entirely rather than adding to it. That is the failure mode: the setting looks applied everywhere right up until one call site quietly opts out, and nothing reports it. Sending a CSRF token to every URL also means sending it cross-origin to whatever a third-party plugin talks to. A wrapper function costs one identifier and makes the behaviour greppable. $.ajaxPrefilter is the middle ground when you cannot reach every call site — it runs for every request, but it can inspect the options and the target URL before deciding to touch anything.