Back to Blog

The AI agent will not show up in your log: whoever lent it the token will

A small office rack with a patch panel, patch cords and stacked network gear

The sentence that gets this into a company is "it is just a connector". Somebody plugs the assistant into SharePoint, the ERP or the ticketing system, and what gets discussed in the meeting is what it will be able to do. What does not get discussed is which identity it will do it with. When the connector goes in under time pressure, the answer ends up being: yours.

You do not need to imagine anybody acting in bad faith for this to end badly. It is enough that three months from now somebody opens the destination system's audit log, sees a large download at three in the morning on a Saturday, and reads, next to it, the name of a person who was asleep. Nobody lied. The token did exactly what it was issued to do, and the log pointed at exactly whoever was named in it. The investigation starts with the wrong person because the design decided that months earlier, on an afternoon when nobody was thinking about logs.

This is not our opinion: it is written into the spec, in capitals

The open standard on which much of that connection is being built is called the Model Context Protocol (MCP). It is not the only route — there is direct REST, vendor-native connectors and integration platforms — but it is the one settling into common ground. Its specification is versioned by date, and the revision in force as of today is 2026-07-28. We read it end to end because there was one thing we wanted to check: what exactly it says about credentials. It says quite a lot, and it says it in the normative vocabulary of the RFCs, the one where MUST and MUST NOT are not suggestions.

In the token handling section of the authorization specification there are three consecutive sentences that are worth the whole article. The last one is this: "MCP servers MUST NOT accept or transit any other tokens". Transit is the load-bearing word there: merely relaying somebody else's token does not turn the server into a neutral pipe. And in the security best practices document there is a section with a name of its own, "Token Passthrough", catalogued literally as an anti-pattern, which ends with a single line of mitigation: "MCP servers MUST NOT accept any tokens that were not explicitly issued for the MCP server".

Here is what we think, flagged as our own reading: a spec does not devote an entire section, with its own risk list and its own mitigation, to forbidding something nobody does. The anti-pattern is described in that much detail because it is the short path. Forwarding the token you already hold is one line of code; requesting one of its own for the connector means registering an application, giving it an identity, deciding permissions and explaining it to somebody. When the sprint is tight, you know which of the two wins.

The paragraph whoever signs off on compliance should read

The most useful part of that section is the list of why that follows the prohibition. One of the blocks is headed "Accountability and Audit Trail Issues", and it contains this sentence, which is the one holding up this article's headline:

«The downstream Resource Server’s logs may show requests that appear to come from a different source with a different identity, rather than the MCP server that is actually forwarding the tokens.»

The wording is worth keeping in the original: the complaint is about which party the log names.

MCP Security Best Practices, revision 2026-07-28.

Two things that look alike need separating here, because a technical reader is going to object at this point and is right to. One is token forwarding: the connector accepts a token that was not issued for it and passes it through unchanged to the destination system. That is what the spec forbids. The other is delegated access, where the application has an identity of its own and acts on behalf of a person with their consent. That is a legitimate mode, it exists on every platform, and there it is correct for the person's name to appear in the log. The spec's complaint is not that a user shows up: it is that the intermediary does not show up too, because the token arriving downstream is opaque and the destination cannot tell who presented it.

From which comes our own reading, flagged as such: when the intermediary is not on record, an incident investigation starts with the wrong person. The good news is this does not need arguing about in a meeting, because it can be checked in ten minutes: have somebody make the agent read a document, then open the destination system's audit log and look at the name. If the agent is nowhere to be found, you have your answer. It is the cheapest test in this whole article, and we repeat it at the end, because it is the one you have to run.

The same section warns about something else worth reading slowly: if the server passes tokens without validating their claims — roles, privileges, audience — "a malicious actor in possession of a stolen token can use the server as a proxy for data exfiltration". And it opens the list with control circumvention: the rate limits, request validation and traffic monitoring you have in place tend to depend on the token audience or other credential constraints. With the wrong audience, those controls simply never apply.

It is the same category error we wrote about a few days ago regarding a database privilege granted for its name rather than for what it permits: the decision gets made by looking at the label — "connector", "integration", "read only" — instead of at the scope. The difference is that there the one getting it wrong was an administrator reading a word; here the one getting it wrong is the log, which is the only tool you have for reconstructing what happened.

The connector running on your machine does not do OAuth. The spec says it should not

All of the above applies to connectors talking over HTTP. But a large share of what is installed today does not talk over HTTP: it talks over stdio, meaning it is a process the client launches on the same machine and communicates with through standard input and output. For those, the protocol requirements section is uncomfortably clear: "Implementations using an STDIO transport SHOULD NOT follow this specification, and instead retrieve credentials from the environment".

Translated into what a company actually has: that connector has no consent, no audience, no scope and no expiry. It has the environment of the machine that launched it. The .env with the API key. The laptop's kubeconfig. The SSH agent socket. The variable holding the personal repository access token somebody added "just to test" back in March. The best practices document itself, in its section on local servers, asks clients to warn the user that "MCP servers run with the same privileges as the client", and goes as far as offering, as an example of a malicious startup command, a curl posting ~/.ssh/id_rsa to somebody else's URL.

We already wrote about this family of surprises when we described how locking the SSH agent disabled precisely the restrictions you had put on it. The pattern repeats: the tool holding the credentials has a default behaviour nobody has read, and the default always leans towards things working, not towards things being shut.

The default permission is "everything on offer"

Suppose the connector does do things properly and asks for its own token. What remains is deciding what for. The spec has a section called "Scope Selection Strategy" with a two-item priority order. The first: use the scope parameter the server placed in the WWW-Authenticate header of its 401 response. The second, verbatim: "If scope is not available, use all scopes defined in scopes_supported from the Protected Resource Metadata document".

Now the part that has to sit next to it so as not to cheat, because that rung comes with a limit attached. The spec's very next sentence says scopes_supported "is intended to represent the minimal set of scopes necessary for basic functionality", with the rest requested incrementally through step-up authorization when a particular operation calls for it. And the best practices document, in its scope minimisation section, explains why that second rung exists: MCP clients are general-purpose and lack the domain knowledge to pick permissions on their own, so the spec would rather the decision be made by the authorization server and by the person on the consent screen. It is a deliberate division of responsibility, and sending the scope parameter is a SHOULD for the server, not a MUST.

What strikes us is that this division has a real recipient, and it is not the one you would picture. Whoever decides the scope is whoever clicks "Allow". In most companies we know, that person is not the security lead: it is whoever was setting up the connector on a Tuesday afternoon, facing a screen full of permissions they had not asked for and a green button. And the spec itself knows the catalogue is usually inflated, because its scope minimisation section opens the common-mistakes list with this one: "publishing all possible scopes in scopes_supported", followed by "using wildcard or omnibus scopes (*, all, full-access)". The rule is well written. It is the catalogue that almost never lives up to the rule.

And yes, the official SDK has had its own

There is an assumption almost nobody states out loud when a corporate assistant gets built: that if two employees talk to the same assistant, what one sees the other does not. That assumption has a documented expiry date. On 4 February 2026, advisory GHSA-345p-7cg4-v4c7, CVE-2026-25536, was published against the official TypeScript SDK (@modelcontextprotocol/sdk). Score 7.1, vector CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:N. It affects 1.10.0 through 1.25.3 inclusive; fixed in 1.26.0.

What it did is two things, and both are about reuse. The first: when a single StreamableHTTPServerTransport instance serves requests from multiple clients, JSON-RPC message IDs collide and responses get routed to the wrong HTTP connection. The second: when a single McpServer instance is connected to several transports, the internal this._transport reference is silently overwritten, which drags along final responses, progress notifications and sampling requests. In plain terms: one person's answer could end up on somebody else's screen.

It is worth not overstating it, and we say that as the ones telling you about it. It is a 7.1, with low integrity impact. The vector carries PR:L, which on the CVSS scale means the attacker needs basic user privileges; our reading of that, in this particular scenario, is that the attacker is the other employee with their legitimate session. There is no public evidence of exploitation, and it has been fixed since February. What strikes us as useful about the data point is something else: the separation between users, which everybody takes for granted, was from 1.10 through 1.25.3 a property of the code and not a guarantee of the protocol. And that there is a very concrete, very cheap question — "which SDK version is that running?" — which almost nobody asks.

The seven questions we ask before connecting anything

We automate with AI and make a living from it, so this is not an article against it. We run self-hosted n8n for internal tasks — including publishing to LinkedIn over a webhook — and we treat it as what it is: a production service, inventoried, with an owner and an update window. This is the list we go through before handing anything automated a credential of ours or of a client's.

  1. Which identity does it act under? If the answer contains a person's name, we stop. An agent needs its own identity in the directory, with its own name, owner and review date. It is more work. It is the work.
  2. What audience does the token carry? If the connector forwards the same token the client hands it on to the destination API, it is doing exactly what the spec forbids in capitals. The token upstream and the token downstream are two different tokens, and that is by design.
  3. Which permissions did it actually request? Not what the README says: what appeared on the consent screen, and what is registered today against the application in the directory. Both places, because they do not always match.
  4. Where does it run and with what environment? If it is stdio, it inherits the environment of the process that launches it. At that point the question stops being about the connector and becomes about the machine: which keys live in that environment, and who else can start processes there.
  5. Which SDK version? For the TypeScript one, 1.26.0 or later. And with the number written down somewhere that is not the memory of whoever installed it.
  6. How does it get switched off, and who switches it off on a Saturday? A switch only the person who built it knows how to operate is not a switch. We already described how this ends in the AI pilot nobody switched off: they do not get turned off by decision, they get turned off when somebody trips over them.
  7. Does it show up in the log under its own name? An acceptance test, no theoretical discussion required: have somebody make the agent read something, then open the destination system's audit log and look at who appears. If a person appears, you have your diagnosis, and you have it in ten minutes.

When we say no

There are three situations where we recommend not connecting the agent, even when the project is sold and the demo went down well. The first: when the only integration available is one of the token-forwarding kind and there is no way to request one of its own. That is building on an anti-pattern with a name of its own and hoping that on incident day the logs will say something useful. The second: when nobody can answer who owns the agent six months from now. A service without an owner does not get maintained; it accumulates. The third: when what sits on the other side is a dataset with obligations attached — personnel files, medical records, data about minors — and the agent would ask for read permission over the whole repository because that is all the screen offers.

Saying no in time is cheap. Saying it late has its own statistic too: we already wrote about the forecast that four in ten enterprise agent projects will be cancelled; on that forecast, the weight sat with cost and risk miscalculated up front rather than with the technology. This conversation — which identity it acts under — is exactly one of those that is dirt cheap beforehand and ruinously expensive afterwards. It is what we have been saying here for years in other words: failure is inevitable, an outage is a design decision. A log that points at somebody who was not there is not bad luck; it is a decision somebody made on a Tuesday without realising they were making it.

Do you know which identity your automations act under?

Our AI and automation work starts there rather than with the use case: which agents are already running, with which credential, against which systems, and who switches them off. Alongside it sits Zero Trust, the boring part that holds everything else up — own identity, least privilege, expiry — and the governance of data and applications, which is where you decide what it reaches and what it does not. If on review it turns out you have it well set up, we will tell you so and there will be no invoice.

Talk to everyWAN

Note on sources

Primary sources we read ourselves. The Model Context Protocol specification at modelcontextprotocol.io. The versioning page gives us the revision in force, 2026-07-28. From that revision's authorization specification come: the STDIO transport requirement ("Implementations using an STDIO transport SHOULD NOT follow this specification, and instead retrieve credentials from the environment"), the token handling section ("MCP servers MUST NOT accept or transit any other tokens", plus the obligation to validate that the token was issued for the server itself, per RFC 8707) and the "Scope Selection Strategy" with its two-item priority order, including the second option of using every scope in scopes_supported and the sentence immediately after it stating that this field is meant to be the minimal set necessary for basic functionality. The explanation of why that second rung exists — general-purpose clients without domain knowledge, the decision delegated to the authorization server and the consent screen — is not in the authorization specification but in the best practices document, in its scope minimisation section. From that same security best practices document come the "Token Passthrough" section — with its mitigation line and its risk list, from which we quote the sentence about the destination server's logs and the one about a stolen token used as an exfiltration proxy — the section on local MCP server compromise — source of the warning that they run with the same privileges as the client and of the malicious startup command example using ~/.ssh/id_rsa — and the common-mistakes list from the scope minimisation section.

Vulnerability. For CVE-2026-25536 we take from advisory GHSA-345p-7cg4-v4c7 in the GitHub Advisory Database the title, the publication date (4 February 2026), the 7.1 score, the vector CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:N, the affected range (>= 1.10.0, <= 1.25.3), the fixed version (1.26.0) and the description of both issues: the JSON-RPC message ID collision when a StreamableHTTPServerTransport instance is reused across clients, and the silent overwrite of this._transport when an McpServer instance is connected to several transports. That there is no public evidence of exploitation is, as of today, what we have been able to check; it is not a guarantee.

What is our reading and not the sources'. The most important one, and the one holding up the headline: the spec complains that the MCP server does not appear in the destination logs; the jump from there to "the investigation starts with the wrong person" is ours. Also ours: that a specification does not forbid in capitals what nobody does, and that token forwarding is therefore common; that the real recipient of the responsibility split over permissions is whoever clicks "Allow" rather than the security lead; reading PR:L as "the other employee" in this scenario; the reading that separation between users was a property of the code rather than a guarantee of the protocol; the seven questions and the three cases where we recommend not connecting. The Saturday-night download scenario is an illustrative example we built, not a specific client incident. On our own house: the self-hosted n8n and its use for internal tasks and LinkedIn publishing is ours. Everything was checked on 12 September 2026.

Cover photograph: "Network equipment and cables organized in a server rack at a modern office environment during the afternoon", by Shixart1985, published on Wikimedia Commons under a Creative Commons CC BY 2.0 licence. We cropped it and overlaid our brand text.

IA Automation Identity Zero Trust Cybersecurity
Share LinkedIn X

Subscribe to our newsletter

To receive IT stories, everyWAN news and exclusive subscriber offers, sign up to our mailing list

Minorisa de Sistemas Informaticos y Gestión S.L. © 2026
everyWAN
everyWAN