6 min read

Can IDE extension host identity prove who an agent is?

IDE extension host identity can verify a signed editor process, but shared plugins blur attribution. Use scoped credentials, action approval, and honest logs.

Can IDE extension host identity prove who an agent is?

An editor extension host can carry a valid code signature and still leave you unable to say which extension requested a sensitive action. That is not a defect in code signing. It is the predictable result of asking an operating-system identity mechanism to answer a question that exists inside one process.

This matters when an AI coding agent runs through an IDE, where the host may load several extensions, accept commands from a workspace, and pass work to a gateway that can reach an API or an SSH target. If the gateway approves the host once and treats that approval as proof of a particular extension's intent, it grants more authority than the evidence supports.

I have seen this mistake arrive disguised as a clean security design: verify the signed editor, show the signer in an approval prompt, allow the run. That is a useful control. It becomes dangerous when the prompt implies a precision it does not have. The host may be trustworthy while the request that crossed its boundary remains ambiguous.

A host signature identifies the container, not its occupants

Code signing proves facts about an executable image. On macOS, Apple describes code signing as a way to establish the origin and integrity of software. The system can check that a trusted signing authority signed the code and that the loaded code still matches the signed material. That is exactly the evidence a security decision needs when it asks, "Which application process is asking?"

It does not prove, "Which extension function inside that process asked?" A process has one executable identity at that boundary. If an editor starts an extension host and the host loads ten plugins, the kernel does not mint ten separate code-signing identities for their JavaScript, bytecode, callbacks, or extension API calls.

That distinction has a practical consequence. A gateway can make a defensible record such as:

caller executable: /Applications/Editor.app/.../extension-host
signing authority: Example Software Team ID ABC123
process id: 8421
parent process: Editor.app pid 8304

It cannot derive this from the signature alone:

extension: publisher.cloud-deploy
command: deployCurrentProject
prompt source: chat request 18

The first block is operating-system evidence. The second block is application provenance. Both can be useful, but they deserve different treatment in a log and in an approval screen.

People often call both "identity" and then lose the distinction during implementation. Do not. The signer tells you who produced the box. It does not tell you which passenger reached for the controls.

Shared extension hosts collapse several authorities into one

An extension host exists so the editor can load and coordinate extensions. That design is convenient, but it makes the host an authority bundle. A completion plugin, a formatter, a source control integration, a chat assistant, and a workspace extension may all execute under the same host process.

Consider a gateway that allows an HTTPS call after it verifies the editor's signature. Extension A asks the host to call a deployment endpoint. Extension B has access to an extension API that can induce the same host to make outbound work, perhaps directly, perhaps through a command registered by A. At the gateway, both requests arrive with the same process identifier and signing authority. The gateway cannot separate them by inspecting the host signature.

The ambiguity gets worse when extensions communicate through shared host services. A plugin may register a command. Another plugin may invoke it. A chat extension may receive instructions from a repository file, an issue body, or a pasted terminal result and then dispatch a command. Attribution now has several layers: the signed host, the extension that made the call, the extension that supplied input, and the human or untrusted content that influenced it.

None of this makes IDE extensions inherently unsafe. It means that host-level approval is an approval for the host's combined authority. If that sounds too broad for an operation, you need a second control that sees the operation itself.

An extension name is provenance only when the host binds it

An extension identifier such as publisher.name is useful context, but a gateway should not mistake a caller-supplied string for evidence. Any code that can form a request can write publisher.name into a header, JSON body, command argument, or environment variable. That only tells you what it claimed.

A host can make the claim stronger if it obtains the identifier from its own extension registry, binds it to the active execution context, and sends it across a protected local channel that extensions cannot forge. Even then, the result answers a narrower question: which host-managed extension context initiated this request. It may not identify the prompt, repository content, or person that influenced the context.

The useful test is simple. Ask where each field came from and who could alter it.

FieldWhat it can establishWho can forge or alter it
Host signing authorityThe identity of the loaded host executableAn extension cannot normally forge it
Process identifier and start timeA particular running host instanceThe operating system assigns it
Extension ID in a requestA stated extension identityAny code able to create the request, unless the host binds it
Workspace pathThe host's stated contextThe host or extension can misreport it
Approval decisionA human approved the displayed requestThe approval interface must bind it to the action

This is why "we include the extension name in the audit log" is not a complete security statement. Keep the name. Mark it as host reported unless the architecture gives the gateway a reason to regard it as verified. That label prevents future investigators from treating convenience metadata as proof.

Session approval has a useful boundary and a hard limit

Approving a newly started, verified host process is worthwhile. It catches a different executable, a changed signing authority, a new process lifetime, and a surprise launch path. It also gives the person at the keyboard a chance to see what is about to receive access. For routine work with a narrow credential, that interruption may be the right trade.

The limit is that a session approval grants the whole approved process whatever the session can do. If the process hosts many extensions, it cannot distinguish a request from the extension you expected from a request created by another loaded extension. A clean approval card can communicate the host signer and process identity, but it should not promise plugin-level attribution it lacks.

There is a second failure that teams miss. They approve an editor process in the morning, then install or enable an extension during the same long-lived session. If the host reloads or loads new code without changing the external identity that the gateway checks, the approval remains broader than the person remembers. The appropriate response depends on host behavior, but the principle stays fixed: changes inside an approved host are not automatically visible to a broker outside it.

Use session approval for the question it can answer: "May this signed host process use this category of access while it exists?" Do not stretch it into: "May this specific extension perform this specific irreversible action?"

Per-use approval compensates for ambiguity at the moment it matters

Lock stops approved sessions too
A locked Sallyport vault denies every action, including calls from an already approved editor process.

For sensitive credentials, ask for approval when the action is formed, not only when the host first appears. The prompt should show enough of the proposed action for a person to make a meaningful decision: destination, method or SSH target, credential label, and the portion of the request that creates consequences.

Suppose a host sends this request to a local action gateway:

{
  "channel": "http",
  "credential": "production-deploy",
  "method": "POST",
  "url": "https://deploy.example.internal/releases",
  "body": {"service": "billing", "version": "a1b2c3d"}
}

A suitable approval card should bind the decision to the exact method, destination, credential, and body or a stable digest of the body. It should not say only, "Editor wants to use production-deploy." That wording turns an action approval into a blank check for every call the host can make before the decision expires.

Per-use approval is unpopular because it interrupts flow. That objection is fair for harmless calls. It is weak for a production write, a credential with broad scope, or an SSH command that can change a machine. The person approving does not need to identify the guilty extension with certainty. They need to see the consequence about to leave the machine and decide whether it belongs.

A vault gate adds another boundary that session approval cannot provide. While the vault is locked, deny every action, including calls from previously approved hosts. Sallyport applies that absolute gate before session authorization, and a selected credential can require approval on every use. This makes the product of the controls honest: the host signer identifies the caller, the session decision admits that process for a limited lifetime, and the per-use decision covers the sensitive action.

Narrow credentials reduce the damage of a correct approval

Approval is not a substitute for credential scope. A person can approve the right host and the right request, then still discover that the credential permits far more than the intended operation. That is a credential design failure, not an approval failure.

Split access according to consequence. A token that reads one repository should not also administer every project. A deployment credential should not create users or retrieve unrelated secrets. For SSH, use a separate account or forced command arrangement where the remote side supports it, rather than handing a general shell to a workflow that only needs one maintenance task.

The popular recommendation to give an agent one broad development token is attractive because setup takes five minutes. It is wrong when the token crosses environments or has write authority. A broad token turns every ambiguity inside the extension host into a broad ambiguity outside it. Narrow credentials make the approval prompt easier to read because the available action set already has edges.

For HTTP actions, constrain the destination in the credential record or gateway configuration when the design permits it. A bearer token injected into any arbitrary URL can be exfiltrated by a host that has been induced to call an attacker-controlled endpoint. For SSH actions, record the host, account, and intended command class before you decide that a session approval is enough.

A familiar failure starts with a harmless command palette action

Require a decision per call
Per-key approval shows the action at use time, when host-level identity is too broad.

A developer installs an assistant extension and a deployment extension. Both run in one signed extension host. The developer approves the host when the assistant asks to inspect a staging API, because the approval card correctly displays the editor's signing authority.

Later, the developer opens a repository that contains a task file with instructions for the assistant. The assistant parses the file and invokes a host command registered by the deployment extension. The command asks the same gateway to use a production credential. The request has the same signed process identity as the staging request. A gateway that relies on session approval alone sees an approved caller and proceeds.

Nothing in that sequence requires a forged signature or a compromised operating system. The failure comes from an approval decision that covered the host and a credential that covered an action the developer did not intend to grant. An audit record that says only "approved editor made HTTP call" will not tell the team whether the deployment extension, the assistant, or a task file initiated the sequence.

Change the setup in three places. Require explicit approval for the production credential on every use. Show the destination and release payload in that approval. Record host identity separately from host-reported extension context and retain the connection between the approval event and the call. The request may still be legitimate, but it cannot pass as routine background work.

Audit records need an evidence column, not a flattering story

Logs become misleading when they flatten verified facts and self-reported context into a single sentence. "Plugin X deployed service Y" looks precise, but it can hide an unverified plugin label and an unknown causal chain. Record the raw event with its source of truth.

A useful event shape separates the claims:

{
  "time": "2026-07-24T10:16:43Z",
  "caller": {
    "signing_authority": "Example Software Team ID ABC123",
    "pid": 8421,
    "started_at": "2026-07-24T09:58:03Z"
  },
  "host_reported_context": {
    "extension_id": "publisher.cloud-deploy",
    "workspace": "/work/payments"
  },
  "action": {
    "channel": "http",
    "method": "POST",
    "destination": "https://deploy.example.internal/releases",
    "credential": "production-deploy"
  },
  "authorization": {
    "session_approved": true,
    "per_use_approved": true
  }
}

The point is not to produce more log fields. It is to preserve the boundary between a fact the system verified and a statement the host made. During an incident, that difference determines whether investigators can trace an action or merely repeat a label.

Tamper evidence matters too. A local journal that a compromised process can rewrite is weak evidence about its own behavior. Sallyport projects session and activity views from an encrypted, hash-chained audit log, and sp audit verify can verify the chain offline without a vault key. That does not solve extension attribution, but it prevents a later edit from quietly improving the story.

Isolate the operation when attribution must be exact

Keep SSH keys out of reach
Route SSH through Sallyport's stateless sp-ssh helper instead of exposing an SSH key to the agent.

Some actions need a stronger answer than a shared host can offer. If a credential can move money, alter production access, delete data, or run unrestricted remote commands, route the operation through a component with its own executable identity and a narrow interface. The gateway can then verify that helper rather than infer intent from a crowded extension host.

The helper should accept an explicit request schema, reject extra parameters, and keep its own authority small. For example, a release helper may accept a service name from an allowlist and a version digest, while rejecting arbitrary URLs and shell fragments. The parent editor can still initiate the work, but it cannot turn the helper into a general network client.

Process separation is not magic. If the host can send arbitrary requests to the helper, the helper has simply moved the same ambiguity into a new process. The interface must remove choices that the host should not have. A separate signed helper plus a wide-open "run anything" request is theatre.

When isolation costs too much, fall back to action-specific approval and narrow credentials. That combination gives a human the chance to catch the consequence even when the source inside the editor remains unclear. Do not claim plugin-level certainty unless the design can show where that certainty comes from.

Treat the approval wording as part of the access boundary

An approval prompt changes behavior, so its wording needs the same care as the code that enforces it. If it says "Allow the editor to access deployment," users will learn to approve a category. If it says "Allow this signed extension host to POST this release to this destination using this credential," users can evaluate the action they are authorizing.

Keep the process signer prominent, because it catches the wrong application. Keep the extension name visible if the host provides it, because it helps a person recognize expected work. Label it as reported context when the gateway cannot verify it. People handle uncertainty better when the interface states it plainly than when a polished label suggests a guarantee.

Start by inventorying every credential reachable from an IDE host. For each one, write down the host-level approval it can safely inherit, the action shape that requires a fresh decision, and the exact evidence the audit record preserves. If the answer to "which extension did this?" is a guess, do not grant authority as if it were a fact.

FAQ

What does code signing actually prove for an IDE extension host?

It proves who signed the executable image that the operating system loaded. It can also prove that the image has not changed since signing, subject to the platform's trust rules. It does not identify the extension, prompt, workspace, or user action that caused a call inside that process.

Can a signed editor identify one specific extension?

Usually, no. A signed host can load several extensions and execute their code in the same process, so every extension inherits the host's identity at the operating-system boundary. Treat the signature as an identity for the container, not for each tenant inside it.

Why does an API call from a plugin look like it came from the editor?

The extension can call the host API, but the sensitive broker sees only the host unless the host forwards authenticated provenance. A field that an extension merely supplies is not proof because another extension can supply the same field. The host must bind provenance to the request before it leaves the process.

Is an extension ID enough for sensitive access?

No. An extension identifier helps users and logs, but it is a label unless the host itself attaches it from its loaded extension registry and protects it through the request path. A malicious or confused extension can imitate a caller-provided identifier.

How can I protect a credential used by an IDE agent?

Use human approval for each sensitive use, or place the operation behind an isolated helper whose identity you can verify. Also restrict the action to a named destination and narrow method, path, or SSH command. A host signature can support these checks, but it cannot replace them.

Should each new extension host process require approval?

A new host process may deserve a fresh session approval because it creates a new executable boundary and a new opportunity for injected code or changed extensions. That approval still covers the host process, not one plugin. Require another approval for actions whose consequences are hard to reverse.

How does Sallyport handle an ambiguous host identity?

An action gateway can reject all calls while its vault is locked, ask approval for a new process session, and require approval on each use of selected credentials. Sallyport uses those three controls in that order. The per-use approval matters when the host identity is broader than the authority you intend to grant.

What should an audit record contain for an IDE agent action?

Yes. Record the verified host signature, process identifier, parent process, start time, extension identifiers claimed by the host, workspace, destination, action shape, and approval result. Mark which fields the operating system verified and which the host reported.

Does sandboxing solve extension host attribution?

No. Sandboxing may limit filesystem or network access, but it does not automatically produce a separate cryptographic identity for every extension. Check whether the extension runs in its own process and whether the broker can verify that process before relying on sandboxing for attribution.

When is host-level authorization acceptable?

Use it for permissions that are easily reversed and have a small blast radius, such as a read-only request to one known endpoint. Do not use it alone for production writes, destructive cloud calls, secret export, or unrestricted SSH. The wider the host can act, the more often a person should approve the particular action.

Sallyport

Sallyport runs API calls and SSH commands for your AI agent. The keys stay in a local vault on your Mac; you approve each run and every action lands in a sealed journal.

© 2026 Sallyport · Open source under Apache-2.0 · Oleg Sotnikov