84 npm packages turned malicious in one May attack

Let your agent touch prod.Keep the keys.

Sallyport holds your credentials in a local vault and runs API calls and SSH commands for the agent. You approve runs with a click or Touch ID. There is no command that reveals a stored key, and no export button either.

$brew install --cask olegsotnikov/tap/sallyport

macOS 14+ · Apple Silicon · Apache-2.0 · Free · no account · no cloud

Built for engineers who let Claude Code, Cursor, or Codex touch real infrastructure

Claude CodeCodexCursorWindsurfClineLangChainCrewAIOpenHandsGooseZed
Try it yourself

Approval where you already are

This key requires approval for every use. The call waits for your decision.

claude · ~/infra

sallyport · http.request

PATCH api.cloudflare.com/client/v4/zones/…/dns_records

key cloudflare · flagged approval per call

waiting for approval…

Approval required

http.request → api.cloudflare.com

Developer ID Application: Anthropic PBC

claude node zsh

Key:cloudflareper call
Click Approve to let the call through.or press A/D
The problem

Your agent can read your keys right now

API tokens in .env, SSH keys on disk, OAuth grants in config files. The agent and every package it pulls in can read them all, and one poisoned README can walk them out the door.

Secrets in plain sight

Tokens in .env and shell variables, SSH keys on disk, OAuth tokens in config files. Readable by the agent, its child processes, and whatever npm installed today.

Prompt injection becomes theft

A malicious page or README tells the agent to send a token somewhere new, and the agent complies. It was built to follow instructions.

You find out from the invoice

Without a gateway there is no record of which calls the agent made, where it sent them, or what they carried. Stolen keys surface weeks later, on someone else's schedule.

This is not hypothetical

May 2026

TanStack npm attack

84 malicious versions across 42 packages harvested cloud credentials, GitHub tokens, and SSH keys at install time, then spread through their victims' own packages.

Late 2025

Shai-Hulud worm

Compromised npm packages stole secrets on install and used the stolen credentials to infect the next round of packages.

Aug 2025

Nx S1ngularity

A poisoned build tool scanned developer machines for secrets, tried local AI tools, and shipped the loot out through the GitHub CLI.

All three harvested keys from environment variables and files on disk. Sallyport keeps usable keys out of both.

Your agent doesn't need the keys

The agent sends a request: call this API, run this command on that host. Sallyport attaches the credential inside the app, executes the call, and returns the result. The key never appears in the agent's environment, and a sealed journal shows what ran and who approved it.

The trust model

Fixed decision ladder

Every action climbs the same compiled ladder. There is no policy language to misconfigure and no rules engine to rot; an optional allowlist can skip the session prompt for code identities you trust.

The trust model

1

vault gate

The vault is absolute

The vault starts locked. Secure Enclave and Touch ID gate access to its data. Until unlock, Sallyport denies all actions.

2

per-call keys

Flagged keys ask every time

A key marked "Approval per call" requires a click or Touch ID for every use, including inside an approved session.

3

session gate

One approval per agent run

A new agent process shows one card with its code-signing authority. Approval lasts until the process exits, you revoke it, or the vault locks.

4

observe

Run and record

With per-session approval off, actions run without session cards and remain in the journal.

Vault gate, per-call key, session gate, observe.

What's inside

Everything ships in one signed app

One signed Mac app holds the vault, the approvals, and the journal. There is no account to create and no cloud service behind it.

Absolute vault gate

While locked, Sallyport denies every agent action and all management operations except status.

Encrypted at rest

The vault encrypts key names, providers, host bindings, SSH inventory, settings, and secret values.

Process provenance

Each card shows the caller's code-signing authority and parent chain, including any unsigned process.

Touch ID for changes

Configuration changes can require Touch ID. A synthetic click cannot satisfy the biometric prompt.

Write-blind journal

Sallyport encrypts agent runs and per-call activity as it writes them, then links the ciphertext with a hash chain.

SSH that sees the command

Sallyport sees the full SSH command, checks the host key, and seals a session recording. The private key stays in the app.

Observe mode

Observe mode removes session cards but retains the vault gate, per-call approval, and journal.

No recovery

The vault has no export, reveal, or recovery key. If you lose it, re-issue the stored credentials at their providers.

Channels

HTTP, SSH, and MCP

Your agent connects to Sallyport as a regular MCP server. Everything it does walks the same ladder into the same journal.

HTTP APIs

http.request → api.github.com

The app makes the HTTPS call and injects the credential only during execution. Cross-host redirects do not carry it.

SSH

ssh.exec → deploy@prod-03

A stateless helper opens the connection. The app handles SSH signatures, pins host keys, and seals a session recording; the private key does not enter the helper.

MCP servers

github.create_issue

Proxy local stdio or remote MCP servers through the same gate. Sallyport seals and refreshes OAuth 2.1 tokens.

By the numbers

The stakes

84

malicious package versions in a single npm attack that hunted credentials

0

accounts, cloud services, or telemetry: Sallyport runs entirely on your Mac

1 tap

Touch ID approves a flagged call; a synthetic click cannot fake it

~2 min

from brew install to your first gated call

Limits

What Sallyport doesn't promise

Security tools love to overpromise, so here is our boundary in writing.

Limits

An approved session can still misbehave

Session approval authorizes the process, not the meaning of every request. Use per-call approval for keys that require individual review.

It can't stop native code running as you

Sallyport is not an antivirus. Code running with your user rights may still attack the app or operating system.

It can't read for you

Cards show the caller's code-signing authority and process chain. You must still review the request.

FAQ

Frequently asked questions

How is Sallyport licensed?
Sallyport is free to download and use. The core is open source under Apache-2.0. Planned enterprise components will use a commercial license.
Where do my secrets live?
Inside a local vault on your Mac. Secure Enclave and Touch ID gate access to the vault encryption key. Sallyport encrypts secret values and metadata at rest and does not upload vault data.
Does it phone home?
No. There is no cloud service, no account, and no telemetry. Sallyport works offline except for the services you point it at and the update feed.
What are the system requirements?
A Mac with Apple Silicon running macOS 14 or newer. Intel Macs are not supported.
What happens while the vault is locked?
Agent actions stop. Management requests return only status; all other operations are denied. Unlock requires Touch ID, and locking clears sessions and pending approvals.
Does it work with Claude Code and other agents?
Any MCP client can use the bundled sp mcp shim to access http.request, ssh.exec, and configured upstream MCP servers.
Can the agent ever see my keys?
No. There is no command that reveals a stored credential, and no export or recovery route either. One honest caveat: Sallyport returns server responses as they arrive, so if a target service echoes a secret back in its response, the agent sees that response.
What if I lose access to my Mac?
There is no recovery key. Re-initialize the vault and re-issue credentials at their providers.

Your agent is one prompt injection away from your keys.

Free download. Apple Silicon, macOS 14 or newer. No account, ever.

$brew install --cask olegsotnikov/tap/sallyport

macOS 14+ · Apple Silicon

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