# tabbit-toy proxies a browser AI backend to OpenAI format, membership check included

> This repository takes the session cookie out of a Chromium based AI browser, signs and forwards requests to that browser's web backend, and re-emits the replies as an OpenAI compatible API on localhost, with zero dependencies and no install step. What is worth reading closely is the security posture it ships with, because the proxy starts with authentication off, a health endpoint that reports whether your cookie is still valid, and an unauthenticated route that triggers a credential refresh.

**goehou/tabbit-toy** — 这是一个基于tabbit的研究包，可以转化成OAI格式出来，同时增加了会员认证功能和一键提取cookie的浏览器拓展，方便快速本地快速使用claude gpt等模型

- Repository: https://github.com/goehou/tabbit-toy
- Stars: 500 · Forks: 805
- Language: JavaScript
- License: not declared
- Published: 2026-09-17 · Updated: 2026-09-17 · Language: en
- Canonical page: https://hysenlabs.com/projects/goehou-tabbit-toy

## The proxy starts with authentication switched off

The startup banner prints its own configuration, and one of the lines says authentication is not enabled. That is the shipped default, not an oversight in the documentation: the API key variable is described as optional, defaulting to empty, with empty meaning no verification, and the client setup instructions tell you to fill in any string such as a placeholder key because nothing checks it. Two endpoints make that default uncomfortable. The health check reports whether the cookie is still valid, how many sessions are open, and what the auto refresh state is. A separate route triggers a manual cookie refresh, which pulls a fresh credential out of the local browser. With the key empty, both of those are open to anything that can reach the port, and the only thing standing between a stranger and your account credential is the loopback interface. The client instructions point applications at the versioned base path on that port, so getting the key wrong still produces a working chat client, which is exactly why the mistake is easy to miss.

## The config template ships a signing key and enables check-in

Two things in the shipped environment template contradict the documentation beside it. The first is the signing key. Its comment states that the default key is a specific 32 character hex string, written out in full, and that leaving the variable empty makes the script fetch the key automatically from the vendor's own key endpoint. A shared signing secret committed to a public repository is the kind of thing that has to be rotated by whoever owns it, not by whoever found it. The second is the check-in switch. The configuration table lists it as optional with an empty default meaning off, and the prose says it is off by default, but the template itself sets it to 1. A reader who copies the template as instructed therefore turns on a scheduled, network calling feature that the documentation says they opted out of. The proxy half of the same template is where the defaults are easiest to see:

```env
PORT=8787
API_KEY=
CDP_PORT=9222
COOKIE_REFRESH_MINUTES=360
```

Four lines, and three of them are the security surface: a fixed port, an empty key that disables verification, and the debugging port the refresh feature reads the cookie through. Neither discrepancy is dangerous on its own, and both are the kind of thing that ships because nobody re-read the template.

## Node 18 is the floor and the refresh feature needs 22

The prerequisites list Node 18 or newer and note that the project has no dependencies and needs no install step, which is true and pleasant. The cookie auto refresh then adds a requirement the prerequisites do not mention: it depends on the built-in WebSocket that arrived in Node 22. The file is explicit that on Node 18 and 20 the feature switches itself off and silently degrades to manual configuration, with the rest of the proxy unaffected. The degradation is the right call, but silent is doing real work in that sentence. A reader on the documented floor version will start the service, watch the refresh never happen, and see a cookie that expires roughly seven days later, with the only symptom being a log line rather than a message at startup.

## The extension instructions point at a D drive path

The recommended way to get the session cookie out of the browser is a bundled extension, and the steps for loading it are otherwise correct: open the extensions page, turn on developer mode, choose the option for loading an unpacked extension, sign in to the web backend, then click the toolbar icon and copy the cookie. The path in step three, though, is a literal Windows path from somebody's own machine, with a drive letter, a toy folder and a project folder in it. Nothing rewrites it for the reader. The manual fallback is spelled out more usefully: open developer tools, go to the storage panel, find the cookies for the backend domain, and join each name and value pair with a semicolon and a space. The cookie being copied contains a token marked as inaccessible to scripts, which is exactly why the extension exists and why the manual route is the harder one. The extension ships in the repository as its own folder, so nothing has to be fetched to use it, and the rest of the tree is small enough to read in one sitting: an environment template, a gitignore, the readme, a docs directory, the package manifest, a scripts directory and the server source.

## The version number is read out of the browser by hand

One configuration field is marked required and is also given a default, which is a contradiction worth naming. The value is a Tabbit version string in the shape of a dotted number with a parenthesised build, and the documented way to obtain it is to open developer tools on the backend page and evaluate an expression against an extension API that returns device info, then log the version field. So a field the file insists on is obtained by copying a string out of a console. The template adds two comments that read like research notes rather than documentation: the version travels in a request header with a context prefix, and the model list carries no identifier field, so the selected model is sent as its display name. The second of those is the sort of detail that makes a reverse engineered integration brittle the moment the vendor tidies up their API.

## The probing tools ship next to the proxy

The package manifest describes the project as a reverse proxy for a browser AI backend into an OpenAI compatible API, and marks itself private with a version of 1.0.0, which is one behind the newest tagged release at 1.1.0. Its scripts section is the more interesting part, because it ships the discovery tooling alongside the product: a probe command with three named variants that walk the chat path, walk the model list, and run in a mode that skips the premium tier. The daily check-in section documents its own provenance just as openly, saying it was reconstructed from the interface the vendor's own browser extension calls, listing the two endpoints for status and for signing in, noting that authentication is cookie only, and stating that the request identifier is a 32 character hex value assembled from timestamp bits, a default browser marker and random bits. The reconstruction is documented at the level of the bit layout, which is both the most useful and the most fragile thing in the repository. The project has 500 stars, 805 forks and no open issues, its last recorded push is 2026-08-23, and the root listing holds eight entries with no licence file, no test directory and no continuous integration configuration of any kind.

## Two account systems, two ports, and one protocol

The vendor runs an international and a domestic edition that the file says share an identical protocol, listing the same key endpoint, the same model configuration route, the same completion route, and the same signature, HMAC and streaming formats, differing only in the backend domain and the built-in model list. That is why the domestic edition is supported by changing a base URL rather than by editing code, and why both can run side by side as two instances selected by a profile flag, one on port 8787 and the other on 8788, each reading its own environment file. Two constraints follow from that design and are stated plainly: the two editions are separate account systems and their cookies cannot be mixed, and the domestic browser has to be launched on its own debugging port because the default one cannot be shared. The domestic backend domain is given as an observed value that the file begins and does not finish.

## The check-in loop runs daily at half a minute past midnight

The last feature automates a loyalty activity. The vendor's personal centre has a daily sign-in that pays out usage credits and a desktop pet entitlement over consecutive days, and this project reimplements it in plain HTTP so it starts with the proxy, needs no browser window, does not depend on the debugging port, and sits outside the proxy request path. It checks in immediately at startup and then loops every day at 00:00:30, with no cron or launchd involved, and a separate command runs the same thing standalone for a single round or for one edition only. The technical shape is small and the operational shape is not: it is a recurring, unattended, authenticated call that collects a per-account reward, sharing the credential the proxy keeps fresh. That is fine as a convenience for one person's own account and is a different proposition the moment it is pointed at more than one, which is the line the project does not draw for you.

## Conclusion

Read this as an engineering artifact rather than a recommendation. The reverse engineering is careful, the failure handling is documented, and the auto refresh fallback is the kind of detail most projects omit, but the thing being automated is a membership gate: the premium model tier is conditioned on the account being set as default browser plus a request header marker, and the project satisfies both on the user's behalf. Before running anything like it, fix the defaults that matter, set the API key so the proxy is not an open relay, remember that the cookie is a bearer credential for a paid account and that writing it back into a dotenv file puts it on disk, and do not point the check-in loop at anything but your own single account. Nothing here should be run across accounts, on shared infrastructure, or in place of a licence.

## FAQ

### What is goehou/tabbit-toy?

It is a zero dependency Node project that takes the session cookie from a Chromium based AI browser, forwards signed requests to that browser's web backend, and serves the replies as an OpenAI compatible API on port 8787. It also ships a bundled extension for exporting the cookie and an optional daily check-in routine.

### Does the tabbit-toy proxy validate API keys?

Not by default. The API key variable is optional, defaults to empty, and empty means no verification, which the startup banner confirms by reporting that authentication is not enabled. The client setup instructions tell you to type any string, since nothing checks it.

### Which models does the tabbit-toy proxy expose?

The file lists a default model described as free and unlimited, several Chinese model families described as free and metered, and a premium tier including the higher Claude, GPT and Gemini variants that it marks as requiring a Pro membership. That premium tier is conditioned on the account being set as default browser plus a request header marker, which the project handles for you.

### What Node version does tabbit-toy need?

The prerequisites say Node 18 or newer with no install step needed. The cookie auto refresh additionally depends on the built-in WebSocket from Node 22, and on Node 18 or 20 that feature switches itself off and silently degrades to manual configuration while the rest of the proxy keeps working.

### Does tabbit-toy have a licence?

None is declared. The repository records no licence identifier, the root listing contains no licence file, and the package manifest marks the project private with a version of 1.0.0 while the newest tagged release is 1.1.0.

### Can tabbit-toy run the international and domestic editions together?

Yes, as two instances. The file says both editions share the same protocol and differ only in backend domain and model list, so a base URL is the only change needed, and the two can be started with a profile flag on port 8787 and 8788. Their cookies are separate account systems and cannot be mixed.

## Sources

- [goehou/tabbit-toy on GitHub](https://github.com/goehou/tabbit-toy)
- [Issues](https://github.com/goehou/tabbit-toy/issues)
- [README](https://github.com/goehou/tabbit-toy/blob/main/README.md)
- [Releases](https://github.com/goehou/tabbit-toy/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/goehou-tabbit-toy
