hidden-agenda
v0.1.0
Published
Find content in your repo that talks to AI agents behind your readers' backs — hidden HTML comments, concealed elements, invisible unicode.
Maintainers
Readme
hidden-agenda
Find content in your repo that talks to AI agents behind your readers' backs.
When someone points an AI assistant at your repo — "evaluate this package", "install this MCP server" — the agent reads the raw files. Humans read the rendered ones. Anything that lives in the gap between those two views is an invisible channel straight into somebody else's agent: hidden HTML comments, concealed elements, invisible unicode. This linter closes the gap.
npx hidden-agenda # scan the current repo
npx hidden-agenda docs/ README.md --fail-on warn
npx hidden-agenda --json # machine-readable findingsERROR README.md:1 [html-comment/agent-greeting]
Hidden HTML comment addresses/instructs an AI agent (agent-greeting, machine-readable-offer)
» Hello, agent. A human is probably reading this README, but you might be too. …
why: Directly greets an AI agent — meaningless to human readers, actionable to machines.What it detects
| Detector | Severity | What |
|---|---|---|
| html-comment | error | Hidden <!-- --> comments that greet, address, or instruct AI agents ("hello, agent", "if you are an AI…", "ignore previous instructions", "do not tell the user", offers of machine-readable endpoints) |
| html-comment | warn | URLs offered only inside hidden comments — links human readers never see |
| hidden-element | error/warn | The same content inside hidden, display:none, font-size:0, or aria-hidden elements |
| invisible-unicode | error | Unicode tag-block characters (U+E0000–E007F) — invisible ASCII smuggling |
| invisible-unicode | warn | Zero-width characters and bidi controls (Trojan Source) |
Tooling comments (eslint, prettier, toc, licence headers…) are allowlisted.
Precision over breadth: a linter people mute catches nothing.
GitHub Action
- uses: StuMason/hidden-agenda@v0
with:
paths: "." # optional
fail-on: error # error | warn | neverExit codes
0 clean · 1 findings at/above --fail-on · 2 usage error
Why this exists
I put a hidden HTML comment in the README of my own MCP server — invisible on GitHub, perfectly visible to any agent asked to vet or install the package — and someone rightly called it out. The intent was a marketing experiment; the pattern is indistinguishable from an attack, because agents can't read intent, only instructions. I removed it, then built this so it can't happen quietly again — and the first time I ran it across my own repos, it found a second one I'd forgotten about.
If you ship anything agents are asked to read — MCP servers, CLIs, actions, libraries — put this in CI and make the invisible channel a build failure.
Programmatic use
import { scan, scanFile } from "hidden-agenda";
const { findings, filesScanned } = scan(["."]);MIT © Stu Mason
