Leroy H. Mason (Elior Malak) (@Lhmisme) header
Leroy H. Mason (Elior Malak) (@Lhmisme) profile picture

Independent AI security researcher. Built mcp-authscan, a focused auth scanner for live MCP servers. Finds the boring failures that actually ship.

Georgia, USA
Joined August 2009
Photo by Leroy H. Mason (Elior Malak) (@Lhmisme)Photo by Leroy H. Mason (Elior Malak) (@Lhmisme)Photo by Leroy H. Mason (Elior Malak) (@Lhmisme)Photo by Leroy H. Mason (Elior Malak) (@Lhmisme)Photo by Leroy H. Mason (Elior Malak) (@Lhmisme)Photo by Leroy H. Mason (Elior Malak) (@Lhmisme)Photo by Leroy H. Mason (Elior Malak) (@Lhmisme)Photo by Leroy H. Mason (Elior Malak) (@Lhmisme)Photo by Leroy H. Mason (Elior Malak) (@Lhmisme)Photo by Leroy H. Mason (Elior Malak) (@Lhmisme)
The TypeScript SDK behaves the same way, and one step further. In default configuration it sends Basic credentials to the non-matching token endpoint and then uses the issued token as a Bearer on the resource. Supply an expected issuer and it refuses before reaching the token endpoint at all. I checked the fix diff between 1.30.0 and 1.31.0 to confirm this is the same decision rather than an oversight. The constructor warns at runtime when the expected issuer is omitted, saying the MCP server decides which authorization server receives the client's credentials, and the option is marked deprecated in the type definitions. Stored credentials are bound by default, and a mismatch is discarded rather than sent. Neither SDK leaves this silent. Both warn at runtime, both mark the option deprecated, and both bind stored credentials by default. The gap is a documented compatibility path with a removal date, not an unnoticed one.
21
Day 21 of 30 Days of @boardyai. You can't find a client's flaw by scanning the server, so mcp-authscan now tests the client too. The question it asks is simple. When a server points an AI client at someone the client was never told to trust, does the client hand over its credentials anyway? On earlier real runs, fastmcp 4.1.1 did. Its credential showed up at the wrong server's door. 4.1.2 refused before presenting anything. If the check can't load a client at all, it says so and names the reason. It never reports a pass it didn't see. Receipts over promises.
3
3
143
Leroy H. Mason (Elior Malak) retweeted
I've spent the last few months building @bluebirdaware a non-profit venture. Lanyards & cards designed with people whose conditions aren't visible. 200 surveys and wait list. £10k of donated kit. What I need is a print sponsor for the next run or XL card printer. @boardyai
1
1
1
34
🧐
Cybersecurity is no longer just a career challenge. It's a national security issue. A business survival issue. And increasingly, an international security crisis. The next major conflict may not begin with weapons. It may begin with a keyboard.
38
Do not fear the future. We can and will do this right for humanity.
🤖 Made with AI
43
I foresee the future. Spawning AI or SI agents. BE careful out there, 18 years of technical support!
🤖 Made with AI
6,994
Until August 2025 I was an insurance claims adjuster, and I had never built anything. My background is a criminal justice degree from Columbus State, claims investigation, and law enforcement. I'm from middle Georgia. There were no earlier launches and no earlier businesses. This is the first product I've ever made of any kind. Since then I've become the credited reporter on security flaws in three open source AI projects. I also measured 16,072 AI tool servers from public registries to see how many would let a stranger connect with no credential at all. Of the ones that actually answered, 57.1% did. I taught myself by working with AI agents, and I want to be honest about the split. I decided what to build, who it was for and how it should work, and I did the research. The agents wrote the code and got through documents faster than I ever could. I checked everything they handed back before it went anywhere. That split shaped the tool itself. Years of claims work teach you that a report is a claim made by someone who wants it believed. So every report my scanner produces carries a way for someone else to re-run it and see if they get the same answer. I'm not claiming the tool is always right. I'm claiming you can catch it if it isn't. @boardyai is one of the agents I lean on most, and it pushed me to build that checker. I did this because the gap between how fast AI is shipping and how safe it is keeps getting wider. You don't need a computer science degree to go measure it. Receipts over promises.
3
3
189
Every mcp-authscan report can now be checked by someone who doesn't trust me. @boardyai pushed me to build a verifier, and it's on main tonight. Point it at a report and it recomputes the hash from what's inside. You get one of three answers. It matches. It doesn't match. Or the report was made under an older scheme that today's code can't reproduce, and the verifier tells you that plainly. I ran it on my own published report tonight and got back the same hash I posted, 0049e3dbd616. A test that changes the counts after hashing gets caught every time. The hash leaves out timestamps and run time on purpose, so two runs against the same server can land on the same hash. So far that's proven on my own machine. Other machines and Python versions are next. Receipts over promises. github.com/LHMisme420/mcp-au…
2
1
5
133
Three MCP scanners, one deliberately vulnerable server, three different questions. A content scan asks whether a server's tools are written to do harm. A discovery check asks whether a caller with no credential can see them. An authorization probe asks what that caller can actually do. The fixture is a server on my own machine at 127.0.0.1:9100/mcp, with two tools, read_file and greet. read_file's description tells the model to read ~/.ssh/id_rsa. A resource points at file:///etc/passwd. @boardyai pushed me to add a third tool to the Cisco comparison, so MCPSense 0.4.5 by Faizan Khan ran alongside Cisco AI Defense's mcp-scanner and mcp-authscan. Cisco mcp-scanner, remote scan, yara analyzer only (no LLM analyzer, no API key on the box): 1 finding, HIGH, credential harvesting. 1,775 bytes, exit 0. Cisco mcp-scanner, protocol scan: MCPS-002, MEDIUM, CWE-306. In its own words: "MCP server exposes tool definitions to unauthenticated callers. Tool invocation permissions were not tested." So Cisco answers the discovery question and says plainly where it stops. It also flagged plain HTTP as MCPS-001, which comes from my localhost fixture and says nothing about anyone's real server. MCPSense: 6 findings across 4 check ids, 1 critical, 3 high, 1 medium, 1 low. 7,879 bytes, exit 1. It had the best content read of the three and caught the prompt injection in read_file's description. SEC-005 flagged missing authentication on a server with sensitive tools, based on what the manifest shows, and its report states "No safety or authorization verdict is established." Credit to Faizan for building output that honest. mcp-authscan: ZERO-AUTH MEDIUM on the endpoint, MCPC-2 HIGH on the /etc/passwd resource, MCPC-1 HIGH on read_file, greet clean. Then the scope probe sends no token, a token missing the scope, and a valid scoped token, and records every response. A 403 with insufficient_scope passes. A 200 with a result body fails only when the shortfall was declared in the same run. In my calibration, an open server alone is MEDIUM. CRITICAL needs a demonstrated write, delete, execute or admin surface, and every zero-auth finding states its reason in severity_basis. Run stamps: verdict-v3, probe set 2026.11.07.2, calibration 2026.11.07.1, report hash 0049e3dbd616. I reran both new columns through a script tonight, and they matched the hand runs byte for byte. Receipts over promises. github.com/LHMisme420/mcp-au…
7
1
7
242
I ran Cisco AI Defense's mcp-scanner and mcp-authscan against the same MCP server. Both caught the same bad tool. Only one asked whether that server needs a credential at all. One limitation first, because it shapes everything below. Cisco's scanner ran with its yara analyzer only. Its LLM analyzer didn't run on my machine, so that's one engine, not their tool at full strength. The setup was a deliberately vulnerable server on my own box with two tools, read_file and greet. Cisco scanned both. read_file came back HIGH with one finding. greet came back SAFE. Both correct: read_file's description is written to tell the model to read ~/.ssh/id_rsa and hand it back in the response, and their yara analyzer matches exactly that class of prompt injection and tool poisoning language. mcp-authscan said the same thing in its own terms, MCPC-1 HIGH, greet clean. Same tool, same problem, both right. It also found two things that run didn't: MCPC-2 HIGH, a resource pointing at file:///etc/passwd, and ZERO-AUTH MEDIUM, the endpoint accepting calls with no credential. That's a statement about this run, not proof Cisco can't see resources. The difference is scope, not quality. Cisco's --help lists ten analyzers: api, yara, vulnerable_package, virustotal, meta, llm, behavioral, prompt_defense, schema, readiness. They cover content, packages, schemas and readiness. None is scoped to authentication. In their tool a credential is something you hand the scanner so it can reach protected surfaces. There's a separate protocol subcommand for unauthenticated endpoints, and its own documentation says it "does not call tools or prove that unauthenticated callers can invoke them." So a server can pass their run and still answer anyone who asks. That isn't Cisco getting something wrong. It's a question their scanner doesn't set out to answer, and mine does. Two scanners can disagree on the same server without either being wrong when they're looking at different things. A content scan tells you whether a server's tools are written to do harm. It doesn't tell you who can call them. Those are separate questions, and only one of them is about a credential. Open alone is MEDIUM, not CRITICAL, in my calibration. Some servers are open on purpose, and a public read-only knowledge server is meant to answer anyone. CRITICAL needs a sensitive surface you can actually show: write, delete, execute, admin actions, or record-level data. HIGH is an open server with tools but no visible write or execute. MEDIUM otherwise. Every zero-auth finding carries a severity_basis saying which applied and why. Why it matters past one test server. I walked 16,072 endpoints from named registries. 14,339 of them speak MCP. 8,178 of those completed a handshake with no credential at all, 57.1%. And the open ones tend to skip the rest too: 78.9% of servers that let a client in without a credential return nothing at the discovery path, against 16.3% of servers that ask for one. A 4.8x gap, and it held after dropping every host I couldn't measure. The cut got stricter and the gap got wider, not smaller. The checklist I'd apply to any MCP scan result, including mine: Which analyzers actually ran, and which were skipped? Does any of them test whether the endpoint requires a credential? Does it look at resources, or only tools? Does every check reach a verdict, or say why it couldn't? Is severity tied to what's actually exposed, with the reason written down? Is the run stamped so someone else can reproduce it? A scan that can't answer those six is telling you less than it appears to. Full write-up: This run: verdict-v3, probe set 2026.11.07.2, calibration 2026.11.07.1. Report hash 0049e3dbd616. Receipts over promises. github.com/LHMisme420/mcp-au… View article
7
2
6
278
Correction, same day. MCPSense does flag missing authentication: SEC-005, 'Missing authentication on server with sensitive tools', in that 6-finding report. My line about neither of the other two reporting the open endpoint was wrong for MCPSense. What holds is narrower: it flagged it from the tool metadata and says in the same report that no authorization verdict is established, while its own remediation text says screening cannot establish authorization. Cisco's remote scan reported none. Corrected above. Also, both columns are scripted now rather than remembered. Same fixture, 9100: Cisco mcp-scanner --format raw, 1,775 bytes, exit 0. MCPSense via npx, 7,879 bytes, 6 findings. Identical to this morning's hand runs.
15
Leroy H. Mason (Elior Malak) retweeted
Beat Oklahoma!!! 🐊🏈🔥
🤖 Made with AI
1
11
100
1,236
A read-only token shouldn't be able to call a write tool. On plenty of MCP servers it can, because the server checks that a token exists and never checks what it was issued for. @ihuzaifashoukat named that gap in a comment, and he was right that it was the next check to build. mcp-authscan now has a scope enforcement probe. The verdicts are the point, so here they are plainly. The server refuses a token that lacks the permission and says that's why: PASS. The server hands back a real result to a token that was declared short of the permission before the call: HIGH. It has to be declared up front, because a scanner can't see a token's permissions from the outside. Anything less clear than that is NOT OBSERVED, with the reason named. A plain success with no declared shortfall. A refusal that doesn't say it was about permissions. A server error. None of those prove anything either way, so none of them get counted as a finding or a pass. Eight tests on fixtures, committed as adb2744. Also committed today: the resource read probe, with its test and fixture, 205 lines, f3f53df. One limitation, stated up front: both probes are standalone for now. A normal scan doesn't call either one yet. The scope probe also needs two tokens with different permissions before it can run at all, and a lot of servers will never hand those out, so on live servers it will mostly come back excluded with that prerequisite named. Suite was 482 passing before this, plus the eight new ones. Receipts over promises. github.com/LHMisme420/mcp-au…
6
7
171
I pointed the scanner at the MCP servers people are actually publishing. 6,166 of them could be measured end to end. Of the servers that let a client in without a credential, 78.9% return nothing at the discovery path. Of the ones that ask for a credential, 16.3% do. Same 4.8x gap I reported on 948 hosts, now on the full set, and it holds after dropping every host I couldn't measure. That last part matters more than the ratio: the cut got stricter and the gap got wider, not smaller. The reading I take: missing authentication and missing discovery aren't two problems. They're one posture, and it's the one you end up in by default. 57.1% of the 14,339 servers that actually speak MCP completed a handshake with no credential at all. 16,072 endpoints walked from named registries, in registry order, so this describes what I walked rather than estimating the internet. One limitation, stated up front: I fetched the well-known path directly, so a server that advertises its metadata URL in its 401 challenge is counted as not publishing. Digital Applied got here first at a smaller n and their numbers held up. Receipts over promises. github.com/LHMisme420/mcp-au…
1
2
78
I measured 16,047 MCP endpoints listed in public registries. Two passes over the same hosts. One looked for OAuth discovery metadata. The other asked each server to initialize with no credentials at all. The numbers matter less than how they line up. 5,993 of 16,047 answer 404 at the protected-resource well-known path. No discovery document. Of the 501 servers that challenge for a credential, 61.3% publish discovery metadata. Of the 447 that don't challenge, 15.4% do. A fourfold gap. Missing auth and missing discovery are one posture, not two problems that happen to overlap. A server that didn't build the gate didn't build the document either. Which is the part worth acting on. "Publish a discovery document" reaches the servers who already care. The 447 that skipped the gate skipped the document too, and no amount of documenting changes that. Separately, 23 of the 5,045 servers that do publish metadata advertise an issuer that isn't theirs. 0.46%. Ten sit on a third party's identity provider. Six of those ten are one white-label control plane issuing identity across two customers' domains. The other thirteen are an operator's own subdomain, misconfigured. My thanks to @DigitalApplied whose 1,000-endpoint census on 5 November is what made me want to run this at scale. Method and limits: registry-listed endpoints, not a census of MCP. The cross covers the hosts both passes reached. Two rounds, fixed User-Agent, one request per host per second. Receipts over promises. github.com/LHMisme420/mcp-au…
12
1
5
251
I scanned the hosted FlowState tier today under written authorization from John Martin @dialectforge . Ten checks ran, all ten reached a verdict, and nothing came back as a finding. One check sat out because there's no key set published to read. The part I care about more than the result: every check either reaches a verdict or says why it couldn't. No blank spaces pretending to be passes. Thanks to @boardyai for putting me and John together, and to John for opening a tier for the test and reading the report first.
2
3
112
For the first time, mcp-authscan held a real credential on a live MCP server, so the token check came back with an actual verdict instead of NOT OBSERVED. Today I scanned a third party's hosted MCP server with their written permission. The scope covered their authorization server from discovery through revoke, plus the MCP endpoint on my own account only. Every earlier run of the token CORS check was a read without credentials. That shows a lot, but it can't show whether a live token response can be read from another origin. So the answer was always NOT OBSERVED, with the reason named. This time the scanner registered its own client and got a real token. The token endpoint's success response did not let the tested origin read it. No Access-Control-Allow-Origin on a live token. PASS. The token was revoked at the end of the run. 10 of 10 testable probes reached a verdict. No findings at critical, high, medium or low. Exit 0. One probe was set aside, with the reason named: the host doesn't publish a JWKS endpoint, so there was nothing to test. The rest held up too. Only S256 accepted for PKCE. The registered redirect accepted, and the same address with one character added refused. Client authentication checked before the grant. Password grant not supported. Token responses marked no-store. Issuer, resource metadata and token audience all matched. The team running that server got this right, and now there's a stamped report that shows it. Report hash aa88d577, probe set 2026.11.02.4, scanner v1.1.20. 460 tests passing. Day 18 of 30 Days of @boardyai. Receipts over promises. github.com/LHMisme420/mcp-au…
3
5
106