← All checks
SecurityTypical severity: Medium

HTML Comment Secret Scanner

Scans HTML comments for forgotten keys, passwords or tokens that anyone viewing the source can read.

What it checks

This scanner searches inside HTML comments for keys, passwords or tokens that were left forgotten there. It detects secrets written in comments that anyone can see by viewing the page source.

Why it matters

HTML comments are not private; they reach the browser as-is and anyone can read them with a couple of clicks. A secret forgotten there is as good as published, and it can grant direct access to sensitive services or data.

How to fix it

Remove any comment containing credentials from the published code, and if a secret was ever exposed, revoke it and generate a new one as soon as possible. Always keep keys in server-side environment variables, never in the HTML the browser sees.

How this check works

Scanaris extracts every HTML comment from your main page, meaning everything between <!-- and -->, and searches inside for six secret patterns. Four are recognisable key formats: Stripe secret keys (sk_live_ followed by 20 or more characters), AWS access keys (AKIA and 16 characters), Google API keys (AIza and 35 characters) and private key headers (-----BEGIN PRIVATE KEY----- and the RSA or EC variants). The other two are explicit assignments: password, passwd or pwd followed by a value of at least 6 characters, and api_key, secret, token or bearer followed by a value of at least 16. If any matches, it opens a high-severity finding that names the type of secret found, never the value. The patterns are strict on purpose: a comment that says "token goes here" with no value after it is not flagged.

Why it matters

HTML comments are invisible on the page, but visible in the source, and anyone can see the source with Ctrl+U or a curl. There is no practical difference between putting a key in a comment and posting it on a forum. A Stripe secret key lets someone create charges and refunds; an AWS key, use your account and your bill; a database password, read everything. And automated secret hunters crawl the entire web looking for exactly these prefixes, so the time between publishing the key and someone using it is measured in minutes.

Why it happens

Someone leaves a note for themselves during development ("<!-- admin user / password Temp2024 -->"), comments out a configuration block "to test" instead of deleting it, or pastes an integration example with the real key. WordPress templates and hand-made static sites are the most prone, because their comments reach the browser as they are. In modern frameworks it happens less, but it happens: a comment in a static .html in the public folder or in a component that is not compiled.

How to fix it

  • Rotate the credential first. Assume it has already been read. Generate a new one at the provider, change it on your server and revoke the old one. Then delete the comment; not the other way round.
  • Search the project before deploying, not just the main page:
grep -rnE "sk_live_|AKIA[0-9A-Z]{16}|AIza[0-9A-Za-z_-]{35}|BEGIN (RSA |EC )?PRIVATE KEY|(password|api_key|secret|token)\s*[:=]" --include=*.html --include=*.vue --include=*.php --include=*.hbs .
  • Strip comments in production. Vue and Nuxt remove them at compile time; in Next.js, JSX comments never reach the HTML. For static HTML or WordPress, a minifier (html-minifier-terser with removeComments) or whatever optimisation plugin you use removes them. In PHP, use PHP comments (<?php // ... ?>), which never leave the server.
  • Credentials belong in environment variables, never in files that get served. And add a secret detector to the repository (gitleaks or GitHub's secret scanning) so it does not get back in.

Check it is fixed

curl -s https://yourdomain.com | tr -d '\n' | grep -oE '<!--.{0,200}' | grep -iE "sk_live_|AKIA|AIza|PRIVATE KEY|password|api_key|secret|token|bearer"

Nothing should come out. Ideally the first part, without the last filter, returns no comments either: in production they serve no purpose.

Frequently asked questions

It is a test key, not a production one.

The patterns tell them apart: Stripe's sk_test_ is not flagged, sk_live_ is. If the finding appeared, the format matches a real key or an explicit password assignment. If it really is a placeholder, change it to something that does not look like a credential, such as REPLACE_ME.

Are JavaScript comments checked too?

This check only looks at the HTML. Keys inside JavaScript bundles, with or without comments, are searched by secrets in JavaScript, and references to internal hosts by internal references. What else leaks by accident is in secrets your app leaks in the browser.

Do Internet Explorer conditional comments count?

They are HTML comments and are analysed the same way, but they contain no secrets and are not flagged. Even so, in 2026 they are dead weight: no supported browser interprets them.

Check it on your site

Scan your site free and see if this and 44 other checks pass, with a fix prompt for every issue.

Scan my site free

From the blog

Related checks