# Clipboard credential exposure: stop feeding secrets to agents

Copying a credential feels temporary because the gesture takes less than a second. It is not temporary. Clipboard history, terminal scrollback, agent transcripts, chat sync, and shell history can turn that gesture into several independent copies, each with different access rules and retention.

Developers often focus on whether a secret is encrypted at rest in a password manager. That matters, but the damaging moment comes after the copy. Once plaintext leaves the password manager, it can enter tools built to remember, index, synchronize, or replay exactly what you pasted. An autonomous agent makes the mistake easier to repeat because it invites long, detailed prompts and command output that people treat as disposable.

## Clipboard history creates a second storage system

Clipboard history creates a second credential store when it retains text after the app that produced it has forgotten it. The operating system clipboard is already shared state. A history feature extends the lifetime of that state and often makes old entries searchable.

That is a different risk from an application reading the clipboard at the instant you paste. A developer may reasonably watch a copied value long enough to paste it into a tool, then clear the clipboard. A history database can retain the same value before the clearing action, and it may preserve multiple versions if you copied a token, a secret header, and a complete command.

On macOS, `pbcopy` writes standard input to the pasteboard and `pbpaste` reads it back. That convenience is why scripts and debugging habits so easily pull secrets into the clipboard. Run this harmless test in a throwaway terminal:

```sh
printf '%s' 'CLIPBOARD-TEST-7f3c' | pbcopy
pbpaste
```

The expected output is:

```text
CLIPBOARD-TEST-7f3c
```

Now open every clipboard-history feature you use and search for `CLIPBOARD-TEST-7f3c`. Do the same on any device that shares your clipboard. This test does not prove that a given tool stores every clipboard type, but it shows whether your normal text path keeps an entry after the original operation ends.

Apple documents Universal Clipboard as a continuity feature that lets a user copy on one Apple device and paste on another device signed into the same Apple Account and meeting its continuity conditions. That documentation describes a useful transport mechanism, not a secret-handling boundary. If your credential moves to another device, that device's local applications, backups, and session state join the exposure question.

The usual response is, "I only copied it locally." Local is not a retention policy. A local clipboard manager may run continuously, keep a database for search, include entries in backups, or hand them to a sync provider. A local machine can also have other user sessions, remote management software, screen recording, support tooling, and development utilities. Do not turn this into a vague fear of all local software. Identify what can read your clipboard, how long it retains data, and whether it sends records elsewhere.

A copied secret is not automatically compromised, but it has crossed a boundary you cannot describe with the same confidence as a vault. That should change how you respond.

## An agent prompt is a credential distribution channel

Pasting a token into an agent prompt distributes the token to more places than the request itself needs. The agent can read it, but so can the client that stores conversation history, the context builder that prepares later turns, any logs around the client, and anyone who can inspect the resulting transcript.

The prompt also invites a particularly bad pattern: copying a complete working request because it seems efficient. A developer pastes a bearer token, a URL, a customer identifier, and a `curl` command, then asks the agent to adjust it. The agent may quote the command in its answer. The developer may copy that answer back into a terminal. One secret then appears in the original clipboard record, the prompt, the response, terminal scrollback, and possibly a shell-history file.

Do not try to solve this with a redaction instruction after you have pasted the value. The agent cannot unsee context it already received, and an instruction does not delete local or remote records. Ask for structure, not credentials.

A prompt that exposes nothing sensitive can still give an agent enough direction:

```text
Call the staging inventory API endpoint GET /v1/items.
Use the credential named staging-inventory.
Return the status code and the count of items.
Do not print request headers or authentication material.
```

That prompt separates an action request from authorization material. It also tells the agent what result to return, which prevents the common habit of dumping a full request or response for reassurance.

This distinction gets blurred constantly: a secret reference is not a secret value. `staging-inventory`, `PAYMENTS_TOKEN`, or "use my production deploy credential" can be safe references only if the agent lacks a way to resolve them into plaintext. If a local configuration file expands the reference and then feeds the value back to the agent, you have merely replaced copying with indirection.

Treat prompt text as content that may be retained, searched, reviewed, exported, or accidentally included in a bug report. That standard also applies to agent tool output. A tool that returns request headers, an authorization failure that echoes a URL token, or verbose debug output can put a credential into the next prompt without anyone deliberately pasting it.

## Terminal convenience leaves several copies behind

A shell command with a literal secret can leak through more routes than clipboard history. The shell may store it in history. The terminal may preserve it in scrollback. A terminal multiplexer may write it to a pane log. A recorder can capture it. On some systems, command arguments can be visible to other local processes with sufficient permission.

This is why this familiar command is a bad default:

```sh
curl -H 'Authorization: Bearer eyJ...' https://api.example.test/v1/items
```

The token is visible while you type or paste it, can land in the clipboard, and may persist in the shell's history. Replacing the token with an environment variable removes it from the command line but does not make it disappear from the process environment:

```sh
curl -H "Authorization: Bearer $INVENTORY_TOKEN" https://api.example.test/v1/items
```

That is an improvement only when you control how `INVENTORY_TOKEN` enters the environment, which child processes inherit it, and whether diagnostics print it. Do not paste `export INVENTORY_TOKEN=...` into an interactive shell and congratulate yourself. You may simply move the literal value into history one command earlier.

For manual work, an interactive prompt is often safer because the input does not become part of the command itself. A small script can read a token without echoing it:

```sh
#!/bin/sh
printf 'Inventory token: ' >&2
stty -echo
IFS= read -r token
stty echo
printf '\n' >&2
curl -sS -H "Authorization: Bearer $token" https://api.example.test/v1/items
unset token
```

This prevents the secret from appearing in the typed command and normal terminal display. It does not turn a shell script into a vault. The process still holds the value in memory, `curl` receives a header, and a verbose mode or proxy log can disclose it. Use this pattern for a short manual recovery task, not as a permanent integration design.

The better design keeps the credential outside the command path. Let a credential-aware component issue the request and return only the data the developer or agent needs. If the task is "tell me whether deployment X completed," the result should be a status and a timestamp, not an entire authenticated HTTP exchange.

## Shared clipboard tools widen the audience silently

Shared clipboard tools are unsafe for credentials because sharing changes a local copy into a delivery mechanism. The exposure can involve a teammate's desktop client, a browser extension, a chat integration, a remote workspace, or a device you forgot was signed in.

Developers tend to judge these tools by intent. A shared clipboard exists to help a team move snippets quickly, so it feels like a work channel. Credentials do not care whether the channel feels professional. If every participant can retrieve an entry later, you have granted each participant access to that secret.

The awkward case is the temporary incident channel. Someone needs an API token to diagnose a production failure, and a teammate says, "Drop it in the shared clipboard, I will delete it after." Do not do it. The recipient may paste it into their own shell history. The service may record the item before deletion. A local sync client may download it to several devices. You cannot verify deletion across every copy from your own machine.

Send a reference and establish an approved path to use the credential. If a human must receive a secret, use the organization's designated secret-sharing method with access controls and an expiry. If no such method exists, creating a narrowly scoped replacement credential and revoking it after the incident is generally less reckless than using a collaboration tool as a secret channel.

Clipboard sharing also causes a subtler failure: developers copy a secret locally, then later enable sync, install a history utility, or sign into a second device. Old records can become newly reachable. Check retention and sync settings before sensitive work, but assume that past copying needs its own investigation.

## Clearing the clipboard does not erase the trail

Clearing the current clipboard only replaces the current clipboard contents. It does not guarantee removal from a history database, a sync record, a terminal, an agent conversation, or a destination application's own logs.

You should still clear the current clipboard after accidental copying because it reduces further casual exposure. On macOS, this command replaces plaintext clipboard contents with an empty string:

```sh
printf '' | pbcopy
```

Do not report that operation as remediation. It is containment. The same applies to a clipboard manager's visible "delete" button. It may remove the record from the user interface while backups, sync replicas, indexed search data, or another endpoint retain it.

Handle an accidental copy as a small incident. The right response depends on the credential's scope, but the order matters:

1. Stop using the exposed credential and revoke or rotate it when the issuer supports that action.
2. Clear the current clipboard and delete the known history entry on every device you control.
3. Search the likely destinations: agent chats, terminal history, terminal logs, shell scripts, notes, issue comments, and repository files.
4. Review the credential's service-side activity for actions you do not recognize.
5. Record what happened and fix the workflow that made pasting feel necessary.

People sometimes resist rotation because they cannot prove a third party read the entry. That is understandable during an outage, but the proof standard is wrong. You know the secret reached storage or a channel outside its intended control. The cost of rotation should be weighed against the credential's privilege and lifetime, not against your ability to prove theft.

Do not rotate blindly and then leave an unrevoked old token in a command history. Confirm the old credential no longer works. If the provider cannot revoke individual values, shorten the exposure window by changing the parent secret or access policy, then document the limitation for the next incident.

## Password managers reduce copying but do not erase its risks

Password managers solve the storage problem well when they keep secrets encrypted and gate retrieval. They do not control what happens after an application pastes a value into a prompt, terminal, form, or clipboard history.

Many password managers offer a clipboard-clearing timeout. Use it. It limits the time that the active clipboard carries plaintext. But it cannot reliably erase a separate program's history entry, a synced record, or text already pasted into another application. The feature helps with accidental later pastes. It does not authorize broad copying as a workflow.

The safer move is to use a password manager's integration only for destinations that genuinely need the plaintext and can protect it. An API client that stores secrets in a local workspace file is often a worse destination than it appears. A browser form can leak through autofill mistakes. A terminal command is usually the worst place because developers often paste the same command into tickets and chat when something fails.

Use different judgment for a password that a human must type into a login page and a machine credential used to make API or SSH calls. A human password may have no useful alternative to controlled entry. A machine credential should usually live behind an action boundary so neither the agent nor the human has to move it around as text.

That distinction helps teams avoid an unproductive rule like "never copy secrets." Sometimes a human must copy a recovery code. The useful rule is narrower: do not copy a secret into a system that records, syncs, interprets, or redistributes text unless that system is explicitly approved to hold that secret.

## Credential injection beats prompt-level authorization

Credential injection is safer than prompt-level authorization because the agent requests an action without receiving the material that authorizes it. The agent can say "perform this HTTPS request with credential X," while a separate local component supplies the authorization header and returns a filtered result.

That architecture contains the most dangerous failure mode in agent workflows: the agent exfiltrates a credential simply by echoing it into a file, response, commit message, or follow-up prompt. If the agent never receives the value, it cannot accidentally print it. It can still misuse the authority granted to it, so you need approval and audit controls around the action itself.

SSH needs the same treatment. Copying a private key into an agent context is indefensible. Copying it into a terminal heredoc is only slightly less bad. A proper SSH path keeps the private key in a protected store, performs signing or connection setup locally, and gives the caller command output rather than key material.

Sallyport follows this model for HTTP and SSH: its vault holds API and SSH credentials, while agents request actions through the bundled MCP shim instead of receiving plaintext credentials. Its vault gate, session approval, and optional approval for each credential use control actions rather than asking developers to write policy rules.

Do not confuse this with a network proxy or a general rules engine. An action gateway cannot fix a request that an authorized agent should never have been allowed to make. It can make the authorization visible, require a human decision at the intended boundary, and keep the secret out of the prompt and clipboard path.

## Approval should describe the action, not display the secret

An approval screen should identify who requested an action, what credential authority they want to use, and the operation that will run. It should never require a human to compare or inspect the secret itself.

This is where many homemade wrappers fail. They keep a token in a config file, then print the fully expanded `curl` command for approval. The developer has avoided copying the token into an agent prompt, only to reveal it in the approval dialog and its logs. A safe approval record can show `credential: staging-inventory`, `method: GET`, `host: api.example.test`, and `path: /v1/items`. It has no reason to print an authorization header.

Approval fatigue is a design failure when every harmless read request produces a vague dialog. People click through vague dialogs because the information does not help them decide. A useful decision request shows the code-signing identity of the requesting process, distinguishes a fresh process from an already approved one, and says whether the current action will use a credential marked for individual approval.

Keep the action result narrow too. For example, a deployment status call may return this:

```json
{"deployment":"api-472","state":"completed","finished_at":"2025-04-17T11:26:00Z"}
```

It should not return the request headers, the full body if it contains unrelated customer data, or a debug dump that leads an agent to repeat secrets in later context. Filtering output is not cosmetic. It limits what gets copied next.

## Audit trails should answer whether the agent acted

An audit trail needs to distinguish an agent run from an individual credentialed call. A session record tells you which process received authority and lets you revoke that run. A call record tells you what it did after authorization. One record cannot answer both questions cleanly.

Logs must also avoid becoming another secret vault. Storing the complete request for forensic convenience is tempting, especially during development. Do not log authorization headers, raw cookies, private keys, or request bodies that carry credentials. Record the credential reference, destination, method, path, outcome, time, process identity, and approval decision. Add request identifiers where the target service provides them.

Tamper evidence matters when an agent can act unattended. A log that a process can rewrite after the fact does not settle an argument about what happened. A hash-chained record lets an auditor verify that entries have not been removed or modified without needing to expose the underlying credential material.

Sallyport projects both session and call journals from an encrypted hash-chained audit log, and `sp audit verify` checks the chain offline without requiring a vault key. That is a better incident artifact than a terminal transcript because it records authorized actions without treating every copied string as evidence worth preserving.

When a copied secret incident occurs, use the audit trail to answer concrete questions: Which agent process ran? Which destinations did it reach? Did it attempt a write? Was a session revoked before another call? Those answers help you scope the event. They do not prove that no clipboard reader saw the original value, which is why rotation still belongs in the response.

## The workflow to remove this week

Remove literal credentials from the paths your team treats as ordinary text. Start with the places where copy and paste feels most natural: agent prompts, terminal commands, shared clipping tools, issue comments, and team chat drafts.

Run a short tabletop exercise with a harmless marker such as `CLIPBOARD-TEST-7f3c`. Copy it once, then search the history tools, terminal records, agent sessions, and synced devices your team actually uses. You will find the route that matters in your environment faster than by debating generic security advice.

Then make the safer path less annoying than the old one. Give agents an action interface that accepts credential references, keep session approvals understandable, reserve individual approval for sensitive credentials, and return only the result needed to continue work. If a developer must expose plaintext to complete routine automation, the workflow still has a hole.

A secret should spend its useful life in a protected store and in the process that uses it. It should not make a tour through the clipboard just because copying is easy.
