Grep Found Nothing. The MCP Found Seven.
- Patrick Duggan
- 20 hours ago
- 5 min read
We spent a day pointing our own security tooling at ourselves. It found seven things. The most serious one had been sitting in production for months, and every dashboard we own said it was fine.
Here is what broke, why grep would never have caught it, and how to run the same method against your own stack in about two minutes.
The one that mattered
Our analytics service signs session cookies with a secret pulled from Azure Key Vault. That is the correct design. The code fetches the real secret at startup and stores it in a module-level variable.
It also registers the session middleware at module load — roughly five thousand lines earlier than the Key Vault fetch is awaited. The middleware read a different variable: an environment variable that was never set in production. So it fell through to a hardcoded default string, which is printed in the source file.
Production signed every session cookie with a constant. The Key Vault secret was fetched and thrown away. Nothing consumed it.
Logins worked. Sessions persisted. No error appeared anywhere. Uptime was green. A default that silently works is worse than a crash, because a crash tells you.
Grep cannot find this. Every individual line is correct. The bug lives in the ordering between two lines that are far apart, and in the difference between two similarly named variables.
The pattern underneath all seven
Once we had names for the failures, they turned out to be one failure wearing different hats.
Our own pre-flight tool, Dredd, judges MCP servers before you invoke them. We fed it a server name that cannot exist — pure keyboard mash. It returned ALLOW, severity clean, zero findings, and, critically, dependency graph scanned equals true. Nothing had been scanned. There was nothing to scan.
Dredd could not distinguish "I verified this is safe" from "I have never heard of this." It reported the second as the first.
That is the same shape as a branch protection document in our repo carrying forty-four completed checkboxes while the GitHub API returned 404. The same shape as a test suite passing because it was configured to pass when no tests exist. The same shape as a quarterly access review cadence described as "established" on the strength of exactly one occurrence.
Output without a denominator reads as success. "I found nothing" and "I never looked" render identically, and both render green.
We shipped the fix. Dredd now reports severity unknown, scanned false, and a new field, known to us, when it has no coordinates and no indexed dependencies. It keeps the same three-value verdict so nothing downstream breaks. Absence of evidence is no longer reported as evidence of safety.
Why the MCP approach beat searching
The method that surfaced these was not clever grep. It was asking questions in natural language against an indexed corpus, then verifying each answer against live state.
Searching answers "where does this string appear." That is the wrong question for most real defects. The questions that actually found things were shaped like: is this control operating; what would this check emit if it never ran; does the thing this document claims match what the API returns; which of our indicators has a consumer that only ever queries its own infrastructure.
Those are questions about relationships between systems, not about text. You can decompose each one into fifteen greps and a spreadsheet, or you can ask once against a corpus that already holds the indicators, the decisions, the blog archive, and the KEV catalog, and get a ranked answer with provenance.
The second difference is trust ordering. Before invoking a third-party MCP server, Dredd checks it — server identity plus the transitive dependency graph, against 1.1 million-plus indicators, for the Shai-Hulud and typosquat families. That check happens before the tool runs, not after something goes wrong. Supply-chain compromise through a tool you invoked is not hypothetical; it is the dominant delivery mechanism of the last eighteen months.
What we found in the rest of the sweep
A customer-facing route interpolated an attacker-controlled email sender address straight into an HTML page served to a human. Reflected cross-site scripting on a page whose entire purpose is to be clicked by a suspicious sender.
A compliance route passed a URL parameter directly into a filesystem path join, allowing arbitrary JSON files to be read off the container.
A continuous integration pipeline had been red on every pull request for months, not because of a bug but because the scanner required a GitHub licence tier the repository does not have. It could never have passed. Nobody had checked whether the check was capable of succeeding.
A cloud service principal used by our deployment pipeline held Contributor at subscription scope, granting write access to every resource group including ones not yet created. We replaced it with two resource-group-scoped grants, additively, verifying the new grants landed before removing the broad one.
A retired third-party security vendor had zero role assignments, which looked clean. It also had four custom role definitions still sitting at management-group scope, two of them write-capable, ready to re-grant. Revoked access and removed integration are different statements.
How to run this yourself
Two MCP servers, both hosted, no install beyond a config entry.
Add a server named jeevesus pointing at analytics.dugganusa.com slash api slash v1 slash mcp, with transport type http. It exposes natural-language search across roughly eighteen million documents: indicators, autonomous decisions, KEV entries, adversary profiles, and the blog archive. Search and indicator enrichment are public read. Feed summary needs a free key from analytics.dugganusa.com slash stix slash register, thirty seconds to obtain.
Add a second server named dredd pointing at analytics.dugganusa.com slash api slash v1 slash dredd slash mcp. One tool, check underscore mcp underscore server. No authentication required — it is deliberately frictionless, because a safety check nobody runs is worth nothing.
Then, before you invoke any MCP server you did not write, ask Dredd about it first. And when you want to know whether something is true of your own estate, ask the question in plain language rather than deciding in advance which file to grep.
The part we are least comfortable publishing
The Dredd finding is about our own product. A security tool that returns "clean" for something it never examined is the exact failure that tool exists to prevent. We shipped it that way, and we found it by turning it on ourselves.
We are publishing it because the alternative is the branch-protection document with forty-four confident checkboxes and a 404 behind it. That file was not written dishonestly. It was written as an intention, and then checkboxes made it read as an accomplishment, and nobody reread it for months.
We now generate our compliance posture instead of maintaining it. Fifteen controls, each carrying the exact command that proves or disproves it, reporting what that command actually returned. Statuses are pass, fail, accepted with a recorded owner decision, or unknown. Unknown is never quietly upgraded to pass.
One exception remains in the pipeline, and it carries an expiry date that a control prints on every run, counting down. We know how "temporary" ends otherwise: our lint configuration still carries a rule downgraded "temporarily for the 5.0.2 deployment." We are on 6.0.13.
The question worth stealing
Before you trust any green light, ask what it would say if it never ran at all.
If the answer is the same as success, there is no denominator, and the signal is decoration. Add the denominator, or make the null case say unknown. Never let unknown collapse into pass.
That question cost us one day and found seven things. Two of them were shipping.
Free threat feed and the MCP servers: analytics.dugganusa.com slash stix slash pricing
Every indicator in this post is in the feed. Free.
1.58M+ IOCs, STIX 2.1 / TAXII, 88% novel vs ThreatFox, exploited-CVE leads ahead of CISA. No credit card — a free API key in 30 seconds, and you can audit every claim above against the live endpoints.




Comments