highSeverity: highRisk ratingHow usable this gap is to an attacker. Severity sets the posture penalty: critical −40, high −20, medium −10, low −4, info −1. Higher severity means fix it sooner.Build / source + secret rotationWhere it livesImplementationThis fix is applied in: Build / source + secret rotation. That's the surface you'll edit, DNS, response headers, or a static file.~10 minTime to fixEffortRoughly 10 minutes of hands-on work, propagation aside. Most of these are copy-paste.+20 posture+20 postureScore impactPoints this fix recovers in the ApeCyber posture score (0–100). Posture = 100 minus the severity penalty of every open finding; clearing this finding adds these points back.

Secret in page source: rotate the burned key, then move it server-side

Rotate the exposed key and serve secrets only from the server so nothing sensitive ships to the browser

The threat

The scanner found something in your page source that looks like a secret: an API key, an access token, a private key, sitting in the HTML or in a JavaScript bundle the page loads. Anyone can see it. “View source” in any browser, or a glance at the network tab, and it is right there in plain text.

Treat that key as already compromised. It is not a question of whether someone could read it, they can, trivially, and automated scrapers harvest keys out of public page source around the clock. The moment a real secret ships to the browser it is burned: copyable, and usable from anywhere by anyone, on your account and your bill.

The exact fix

Order matters. Rotate first (the exposed value cannot be un-leaked), then get the secret off the client.

1. Rotate the key now. In the provider’s console, revoke or roll the exposed key and issue a new one. Do this before any cleanup, because the old value is already out and every minute it stays valid is the actual risk. Update your server (step 3) with the new value.

2. Get it out of the client, and out of your source history. Deleting the line from the current page is not enough if it still lives in git history or a cached build:

# stop tracking it going forward
git rm --cached path/to/leaked-config.js
echo "path/to/leaked-config.js" >> .gitignore

If the secret was ever committed, assume it lives in history forever, which is exactly why step 1 is non-negotiable. Purging history (for example with git filter-repo) is good hygiene, but it does not un-leak the old value.

3. Move the secret server-side. A real secret should never reach the browser. Keep it in an environment variable on the server and have your own backend make the third-party call, so the browser talks only to your server, never to the provider with the raw key:

// server-side only: the key lives in the environment, never in shipped HTML/JS
const apiKey = process.env.PROVIDER_API_KEY;

app.get('/api/quote', async (req, res) => {
  const r = await fetch('https://provider.example.com/v1/quote', {
    headers: { Authorization: `Bearer ${apiKey}` },
  });
  res.json(await r.json());
});

“But some keys are meant to be public.” True: browser keys like a Google Maps or Stripe publishable key are designed to ship to the client, and for those the fix is to restrict them (HTTP-referrer, origin, and scope limits in the provider console), not to hide them. This finding is for the other kind, a genuine secret (a private or server key, a full-access token) that was never meant to leave your server. If you are unsure which you have, assume it is secret, rotate it, and check the provider’s docs.

Verify it

curl -s https://yourdomain.com/ | grep -iE 'api[_-]?key|secret|token|-----BEGIN'

Run it against the page, and skim the JavaScript bundles it loads. A clean result finds no live secret in what ships to the browser. The rotated key is the real proof: even if an old copy is cached somewhere, it no longer works.

Proof

The ApeCyber scanner catches this by reading your public page source exactly the way any visitor’s browser can, from the outside, touching nothing, the same way the key leaked in the first place. There is no scary number to attach: a real secret in client-side source is either present or it is not, and the honest fix is to rotate it (the exposed one is burned) and serve secrets only from your server, a clean −20 once nothing sensitive ships to the browser.