Purpose
The purpose of this document is to go into depth about what the FiveM escrow process in, how it’s usually performed, and how I have successfully automated this by bypassing CloudFlare and Cfx bot protections.
Introduction
FiveM is a framework and platform used for the game Grand Theft Auto V. Custom online servers for this game are built using this third party framework. Custom scripts for the servers are developped using a mix of Lua, Typescript, Javascript. Custom 3D models are also very prevelant. FiveM presents a unique challenge when it comes to securing the assets that your team makes. Files such as scripts, textures, and MLO’s are pushed and land directly on the client side. With third party programs these assets are easily extractable, and can be used on other servers even though these assets have not been paid for, and their use has not been authorised.
Cfx in their infinite wisdom have come up with the Asset Escrow service. They describe the service as following:
The Asset Escrow system, developed in partnership with Tebex, provides a reasonable alternative to obfuscation and IP locking. By ensuring purchase ownership, your content will, and can only run on the servers of your customers [or your own server], nowhere else. On top of that, your resources will be encrypted to prevent your work from being leaked. Lua 5.4, YFT and YDR files are the only filetypes supported.
How is the Asset Escrow service accessed?
The Escrow service can be accessed through the Cfx portal. At the time of writing Cfx exposes no API for programmatically accessing the Escrow service.
Accessing the Cfx portal requires logging in with your Cfx account. There are several checks performed at login:
- CloudFlare Turnstile for advanced bot detection. Turnstile uses the following checks:
- Behavioural Analysis & Machine Learning
- Invisible Proof-of-Work / Space Challenges
- Browser & TLS Fingerprinting
- And several others, some of which I’m sure they keep very confidential
- Cfx login rate-limiting. If you login too many times in a short period of time Cfx will block your account from logging in again until their rate limit expires.
- Cfx IP / Geolocation Checks. If Cfx detects you are logging in from a new IP (location) it will send you an email with a link you have to click if you want to continue your login.
These checks are designed to make accessing the portal programmatically impossible:
The Solution: Playwright, Camoufox, and a Proxy
The biggest problem to be overcome by this system is bypassing the CloudFlare Turnstile bot detection. Preventing automated applications accessing systems is exactly what CloudFlare specialises in.
Playwright is Microsoft’s browser automation framework. It programmatically controls real browsers (Chrome, Firefox, Safari, and others) to click, type, and navigate just like a human would. While powerful, vanilla Playwright is easily detected by anti-bot systems.
Camoufox is a Firefox based browser with anti-detection technology, spoofing realistic browser fingerprints (canvas, WebGL, audio contexts, etc.) to make the automated browser use look completely human. It’s essentially stealth mode for web automation.
Camoufox is much better at evading detection versus other browsers like Chromium, which Playwright uses by default.
The rate limiting and the GeoIP tracking done by Cfx can be bypassed by keeping your Playwright login session open and by using a residential proxy that’s a ‘known login location’ for your Cfx account.
The GeoIP tracking used by Cfx. The second entry is my script logging in using my residential proxy, thereby bypassing this protection.
For the proxy, I setup Ngrok and CCProxy on my home machine, and then passed these proxy details to the CfxCourier script. This was handy because my home machine is also the IP that I usually use to login to Cfx usually.
In production, however, you may however opt to use a residential proxy service instead such as Brightdata. Note that these can get pretty expensive depending on your traffic usage.
Buy Residential Proxies - Starting from $2.94/GB - Free Trial
CfxCourier Architecture
AWS Processing Pipeline
The pipeline I’ve designed, named CfxCourier, works as explained below.
- S3 event triggers processing (via EventBridge → SQS)
- ECS Task downloads the file from
unprocessed/
folder in S3 - Playwright uses Camoufox to navigate to portal (reusing existing session)
- Uploads the un-encrypted file and waits for processing
- Downloads the encrypted file and saves it to the
processed/
folder in S3 - Sends a Discord message via webhook with a pre-signed download link, expiring in 60 minutes.
Persistent Browser Pool
CfxCourier maintains a single browser instance running across requests, reusing login sessions to avoid rate limits. The browser auto restarts every 50 requests to prevent memory leaks while health checks ensure reliability.
Resilience
The pipeline handles failures through automatic retries, session recovery, and debug artifacts (screenshots/HTML) saved to an S3 bucket. Structured logging enables monitoring, while horizontal scaling is achieved by running multiple containers with independent browser sessions if necessary.
Architecture Diagram
Developer usage
Workflow for developers would be as followed:
- Be assigned an AWS access key that is unique to them. This access key would be least privilege, ensuring it can only upload to the unprocessed folder in S3.
- Upload their unencrypted asset to S3 either using the AWS-CLI or a third party program such as S3 Browser. These S3 upload events are logged by CloudTrail and can be audited to see who uploaded what file.
- Wait for the file to be encrypted, and for the download link to be sent into discord.
- This encrypted asset can then be pushed to the main code repository.
Out of scope
This is mostly a proof of concept and as such several features were out of scope.
- The script does not support re-uploading / replacing current assets. Each asset uploaded therefore has to be unique in name.
- There is currently no observability / alerting around the ECS task itself, which would be necessary if this was used in production.
- Implementing this workflow in CI / CD. I have not explored this and am not sure if is possible. This would be the final / most helpful step.
Code
https://github.com/bgigurtsis/CfxCourier