DEV Community

RAXXO Studios
RAXXO Studios

Posted on Originally published at raxxo.shop

Leak Sweep Checklist: 7 Checks in One Hour

  • A git-linked hosting project with no framework setting can publish a private repo's root as static files

  • Store file CDNs are public by default, and a rotated secret stays valid until someone revokes the old one

  • Scanners and CLIs can report clean when they skipped the files, so check counts, stderr and decrypt flags

  • Seven read-only checks cover git history, domains, host settings, bundles, CDN files and every credential

A leak sweep is the hour you spend looking at your own stack the way a stranger would. Not your dashboards, not your repo settings, but what anyone on the internet can actually request. After a week of security advisories I turned mine into a fixed checklist, seven checks, all read-only until the last one. Below is where private things usually go public without anyone noticing, the tool traps that make a sweep look clean when it isn't, and the checklist itself.

Where Private Code Goes Public Without Anyone Noticing

Repo visibility is a GitHub setting. It doesn't follow your code anywhere else, and that's where most surprises come from.

The classic case is a hosting project linked to a repo that isn't a web app. Say you connect a theme repo, a docs folder or a scripts repo to a host like Vercel to try something. The framework preset is "Other", the output directory is the repo root, and git deploys are on by default. From then on, every commit builds and publishes the whole repository as static files on the project's .vercel.app domain. Notes, exports, drafts, a token someone pasted into a markdown file years ago: all of it is one URL away, and the repo can still be private on GitHub.

Nothing in the dashboard looks wrong. The host lists projects. It doesn't list what each project publishes. A project you created for a ten-minute experiment keeps building quietly for months, and it shows up on the usage page before it shows up anywhere else.

What a sweep checks here:

  • every hosting project's framework preset and output directory, because "Other" plus "." is the shape to look for

  • which projects have git deploys on, and whether you still need them

  • deployment protection on every project, because preview URLs are public otherwise, and every old preview of every branch stays reachable

The fix for a project nobody needs is deleting it. Every deployment URL then answers 404 DEPLOYMENT_NOT_FOUND within about a minute. Check that from outside rather than trusting the success message.

One more variant: a production domain usually has a .vercel.app alias next to the custom domain. Protection settings that cover previews often don't cover that alias, so request it directly during the sweep. Whatever answers there is as public as your homepage.

Client-side bundles are the other common route. Anything in a NEXT_PUBLIC_ or VITE_ variable ships to the browser by design. A variable called NEXT_PUBLIC_SOMETHING_SECRET is a leak with a name tag. Source maps can publish your original source next to the minified files.

Files and Secrets That Outlive Their Purpose

The second family of leaks is things that were fine once and nobody cleaned up.

Store file uploads are a good example. A Shopify store's Files section serves everything from a public CDN with a predictable path. The admin page calls them Files. Nothing on it says public. If a paid download, a price export or an internal PDF ever got uploaded there to share it quickly, it stays downloadable without a login until someone deletes it. Delivery of paid files belongs behind a signed, expiring link from your own server.

Secrets have the same lifecycle problem, with a twist. Many developer dashboards rotate a secret by creating a second one. You get an "Old" and a "New", both valid, and a separate button to revoke the old one. Rotate, update your env files, move on, and the old secret keeps working for as long as nobody clicks revoke. If that old value ever sat in a commit, rotation didn't fix anything.

Two habits close that gap:

  1. Before you revoke, move every consumer to the current secret: CI secrets, hosting env vars for production and preview, local env files. Otherwise the revoke breaks a pipeline at 2am.

  2. After you revoke, prove it. Request a token with the old secret and expect a refusal, then with the new one and expect success. A revoke you didn't test is a revoke you're assuming.

Every credential a scan finds deserves the same treatment before you report it. Test it with a free, read-only call (most APIs have a "list stores" or "list models" endpoint) and you know in seconds whether it's live. A 401 means dead and you can relax. A 200 means you have work to do now.

Five Tool Traps That Make a Sweep Read Clean

The leaks are usually the easy part. The hard part is that your own tools can quietly report "clean" when they never looked.

grep may skip your env files

On some setups grep is an alias for ugrep or ripgrep, and both respect .gitignore by default. Search your env files for a client ID and you get zero hits, which reads as "nothing uses this". It means "I didn't look". Use /usr/bin/grep, or ripgrep with --no-ignore --hidden.

CLI logs often go to stderr

Plenty of CLIs print their log tables to stderr. Add 2>/dev/null to keep the output tidy and you throw away exactly the lines you're searching for, so every check reports zero matches. Use 2>&1 when you grep logs.

"decrypt=true" doesn't always decrypt

Some env APIs return encrypted envelopes from their list endpoint even when you ask for decrypted values, and only the single-variable endpoint returns plaintext. If every value starts with the same base64 prefix, you're looking at ciphertext. Test it as a credential and you'll get errors and wrongly conclude the secret is dead.

Your redaction can print the secret

BSD sed on macOS doesn't support \s. A masking pattern built on it matches nothing, and the unmasked value lands in your terminal and its scrollback. Redact with a small script that asserts it matched exactly once before printing anything.

A zero-second scan may have scanned nothing

A secret scanner that finishes a big repo in "0s" might be fine, or might have read zero commits. gitleaks prints how many commits it scanned at info log level. Read that number for at least one large repo before trusting a wall of zeros.

The 7-Check Leak Sweep

Everything here is read-only until the last step, and the whole pass takes about an hour for a small studio stack. I run it after every wave of security advisories and whenever I connect a repo to a new host, which is exactly when these mistakes get made.

  1. Git history: run gitleaks on every repo with all refs. Mirror-clone your public repos fresh, so the scan matches exactly what the world sees. Check the commit counts.

  2. Every hosted domain: request /package.json, /.env, /.git/config and your notes files. Compare each response with the homepage first. Same bytes means the app's fallback page, not a leak.

  3. Host settings: framework preset, output directory and deployment protection on every project.

  4. Client bundles: download each site's JS chunks, grep them for key patterns, and request the .map files. Check public env variable names for KEY, SECRET or TOKEN.

  5. CDN uploads: list files in your store and storage buckets, and look for zips, PDFs and exports that should sit behind a check.

  6. Every credential you find: test it with a free read-only call. Compare values by hash against your env file instead of printing them.

  7. Revocation: move consumers to the current secret, revoke the old one, then prove the old one fails and the new one works.

For the runtime side of security hygiene, my eMudhra CA Break: Patch List for 6 Runtimes covers the patch floors and a probe for each runtime. For testing the code itself, Claude Formal Verification, the 1-Hour Version shows the property tests I'd write first. And the review every new tool gets before launch is in The Security Review Every RAXXO Tool Passes Before Launch.

Bottom Line

Most leaks in a small stack aren't clever. Usually it's a hosting project nobody configured, or a secret that got rotated and never revoked. They keep running because nothing ever looks at them from the outside. A sweep fixes that: request what a stranger can request, test every credential you find, and don't believe a clean result until you've seen the same check catch something.

I run the sweep with Claude Code, and the parts that repeat are hooks now. The Claude Blueprint is that setup, packaged. When did you last open your own project's .vercel.app domain and read what came back?

This article contains affiliate links. If you sign up through them, I may earn a small commission at no extra cost to you. (Ad)

Top comments (0)