In a CSRF attack, the attacker causes the victim to send a request (the Cross-Site Request that is being Forged) to the server. The victim's browser sends its own cookies, not ones the attacker either knows about nor can control (at least, this is the assumption). As such, so long as each user gets a unique anti-CSRF token (it can be totally random, and if it's long enough there is still ~0 risk of collisions), an attacker can't use their own anti-CSRF token for a forged request, because it won't correspond to the victim's cookie (or match the anti-CSRF token expected for the victim using any other method either).
With that said, the "double-submit cookie" pattern that you're describing here is weak, and should be avoided. The problem is that the assumption "attacker can't set cookies for the victim" isn't a very good one. Cookie security is kind of a mess for historical reasons, and while there are ways to protect cookies that have been bolted on over time, they're not yet in widespread use. For example, an attacker can add their own cookie for the site using either a non-HTTPS request that they (as a man-in-the-middle) intercept and return a set-cookie header on (they can do this if the victim ever visits any non-HTTPS site, even if the target site doesn't even listen for plain HTTP!), or by gaining control of any subdomain that shares a root domain with the victim site and setting a cookie scoped to the root. In such cases, the attacker can in fact just get their own anti-CSRF token and anti-CSRF cookie, set the latter on the victim's browser, and then forge requests using the former.
A few much safer patterns than double-submit cookies exist.
- Session anti-CSRF tokens, stored server-side, are a classic solution. However, they add significant server-side workload (either checking a DB or keeping a cache of valid values in sync across a cluster) on every state-changing request. As such, they are considered unsuited for highly-scalable apps.
- Anti-CSRF tokens tied to the session/access token, typically via a hash (HMAC isn't needed; if the attacker knows the victim's auth token it's already game over). The server needs some way to identify each user (opaque session token, JWT, whatever), and the added workload to hash this auth token and check it against a submitted anti-CSRF token is trivial).
- Use of API requests that are not valid "simple" requests for CORS, and as such require a pre-flight. Ways to do this include requiring a content type such as application/json (you do have to actually require that content type, though, not just that the request is parsable as JSON or that the content type header contains the text "application/json" somewhere), or requiring the presence of any custom header (it can be completely static, such as "X-CSRF: no"). Telling the victim's browser to send such a request from any third-party origin will cause a CORS pre-flight request, to which the server will not allow the actual request (unless you fully trust the relevant third-party origin, which you shouldn't in this scenario because it's an attacker-controlled one). CORS is not intended as an anti-CSRF measure, and people try to misuse it as one all the time (e.g. by checking the Origin header alone, which is not present on all cross-site requests!), but the security behavior of pre-flight request requirements is standardized.