Encrypted file transfer for AI agents
AI agents need to exchange files. The default options (public S3 buckets, base64 blobs in tool calls, plaintext download URLs in chat messages) all leak data, expose attack surface, or both. AgentDrop is the MCP server that encrypts every file transfer between agents end-to-end. This page covers the threat model, the cryptography, and why client-side encryption is non-negotiable for autonomous workloads. For MCP host setup details (Claude Code, Cursor, Windsurf), see MCP server for file transfer.
The problem isn't file transfer. It's threat model.
Most file-transfer infrastructure was designed for humans. A human notices when a download URL looks suspicious. A human can verify the sender face-to-face. A human pauses when a file extension doesn't match the described content.
AI agents do none of that.
An agent that decides on its own when to fetch a file at 3am has no UI. No confirmation dialog. No instinct that says "this URL pattern looks weird." It executes whatever the protocol tells it to. If the protocol leaks plaintext through a logging pipeline, the data is leaked. If the protocol authenticates via a shared bearer token, anyone with that token impersonates every agent on the system.
When we built AgentDrop, the assumption we started from was: every file transfer happens unattended. There's no human in the loop to catch problems. That changes what "secure file transfer" has to mean, compared to a Dropbox link or a Google Drive share. The cryptography has to survive an environment where the receiving software is the only line of defence between the data and an attacker who has compromised an upstream dependency.
The four wrong ways agents share files today
Plaintext URLs in tool-call arguments
Agent A signs an S3 presigned URL with a 30-day expiry and hands it to agent B inside a tool-call argument. The URL ends up in:
- Agent A's LLM provider request log (OpenAI, Anthropic, Google)
- Agent B's tool-call history
- Whichever observability stack either agent uses (Langfuse, Helicone, Phoenix)
- Possibly a CSV export from any of those tools
By the time you discover the leak, the URL has been seen by 4–6 third parties. None of them are malicious; the threat model just doesn't account for them.
Public buckets with obscure paths
"It's behind a UUID, no one will guess it." Search engines index public buckets. AWS publishes anonymous-bucket alerts. Within hours of going public, a bucket with /secret-uuid/ paths gets enumerated by someone's Shodan-equivalent.
Shared filesystem mounts
Common in self-hosted setups: agent A and agent B both mount /shared. Works until agent A is compromised. Then everything in /shared is exfiltrated in one shot. There's no compartmentalisation between transfers, no per-transfer authentication, no way to revoke access without unmounting the volume from every agent that touches it.
Base64 blobs in chat messages
If the file is small enough, base64-encode it and pass it inline. This actually transmits the file safely if the chat transport is encrypted. The problem: you've now pinned the file's contents into every conversation log, every replay buffer, and every retention window of the chat platform. The file's lifecycle is no longer under your control.
What "encrypted" actually means
There are five places encryption can apply, and most platforms apply only one or two:
- In transit (TLS) - between the client and the server
- At rest (AWS SSE, GCP CMEK) - on the storage backend
- Server-side - the platform encrypts but holds the keys
- Client-side, server holds key - the zero-trust illusion: server still has access on demand
- Client-side, server never holds key - true end-to-end
TLS plus at-rest encryption is what AWS S3 gives you out of the box. It's enough for compliance checkboxes. It's not enough for AI agents because the platform itself can read your files. If the platform's database leaks, your files leak. If a rogue support engineer queries the bucket, they see plaintext. If a court order arrives, the data is producible.
For AI agents - especially when one agent is processing another agent's output - option 5 is the only choice that survives platform-side incidents. The encryption keys live with the agents, not with us. We can't decrypt your files. We don't want to. The architecture makes it impossible.
How AgentDrop encrypts every transfer
Three pieces fit together: identity, key exchange, and per-file encryption.
Identity - X25519 keypairs
When you register an agent on AgentDrop, the SDK generates an X25519 keypair locally. The public key is uploaded; the private key never leaves your machine. Our server stores only public keys. There is no API endpoint that returns a private key - we don't have it. The register-agent endpoint accepts only the public half. If you lose your private key, you re-register the agent. We can't recover it for you.
Key exchange - X25519 ECDH
When agent A wants to send a file to agent B, the SDK pulls B's public key, generates an ephemeral keypair for that specific transfer, and computes an ECDH shared secret. This means every transfer derives a fresh key - even between the same pair of agents. If one transfer's key is compromised, only that one transfer is at risk. There is no long-lived shared secret to steal.
Per-file encryption - AES-256-GCM with HKDF-SHA256
The shared secret feeds HKDF-SHA256 with a per-pairing salt to produce an AES-256 key. Files are encrypted with AES-256-GCM in chunks, with a fresh IV per chunk. The ciphertext, the IVs, and the ephemeral public key get uploaded to our R2 buckets. The recipient's SDK reverses the process locally. We see encrypted blobs we cannot decrypt.
Integrity
AES-GCM is authenticated encryption - any modification to the ciphertext fails decryption with an explicit integrity error. Our server can't tamper with files in transit. Neither can a man-in-the-middle attacker between the SDK and our servers. If the bytes change, decryption fails loudly. The receiving agent gets an exception, not corrupted data.
The whole exchange happens through one SDK call.
Python:
import os
from agentdrop import AgentDrop
ad = AgentDrop(api_key=os.environ["AGENTDROP_API_KEY"])
transfer = ad.send_file(
recipient="bob",
file_paths=["/path/to/report.pdf"],
message="Q3 financials"
)
print(transfer.id)Node.js:
import { AgentDrop } from 'agentdrop'
const ad = new AgentDrop({ apiKey: process.env.AGENTDROP_API_KEY })
const transfer = await ad.sendFile({
recipient: 'bob',
filePaths: ['/path/to/report.pdf'],
message: 'Q3 financials',
})
console.log(transfer.id)The SDK does the keypair lookup, the ECDH derivation, the AES-GCM encryption, the chunk upload, all of it. From the developer's perspective: one call, encrypted file delivered.
Why we picked these primitives
X25519 over P-256. X25519 is constant-time by construction, simpler to implement correctly, and avoids the trapdoor concerns the broader cryptography community has flagged about NIST curves. Signal uses it. WireGuard uses it. The threat model for AI-agent communication is closer to those use cases than to TLS web traffic, where P-256 is dominant for ecosystem reasons rather than security reasons.
AES-256-GCM with per-chunk IVs. Streaming files (we support up to 10 GB on the Scale tier) means we can't load the whole file into memory before encrypting. Chunked AES-GCM handles streaming with authenticated encryption per chunk. If a chunk arrives corrupted or tampered with, only that chunk fails - not the entire transfer. The IV space is large enough that birthday-bound concerns don't kick in for any plausible file size.
HKDF-SHA256 for key derivation. Separates the long-term X25519 secret from short-term AES keys. Per-pairing salt means even if you send 10,000 files between the same two agents, every file gets a unique encryption key. No long-lived key reuse, no opportunity for cryptanalysis to chip away at a repeatedly-used key.
We picked these primitives at design time and have re-read the threat model on a recurring basis since. Nothing has surfaced in the cryptography literature or in our own production telemetry that would make us want to change them.
Built for one specific problem
AgentDrop is purpose-built for one thing: an autonomous AI agent producing an artifact and handing it to another autonomous AI agent, possibly across organisations, possibly hours or days later, with strong cryptographic guarantees about who can read it. Every architectural choice on this page flows from that. Files measured in MB and GB, asynchronous delivery, agent-first identity, scoped credentials, server-blind encryption: this is what shipping file transfer for AI agents actually looks like.
Where to go next
If you want to send your first encrypted file between agents in under 60 seconds, start with the quickstart.
If you want the full encryption protocol details - algorithms, IVs, key sizes, exact wire format - read the encryption guide.
Related topic pages:
- Send files between AI agents - broader awareness page on agent-to-agent file flows
- Zero-knowledge encryption for AI agents - deep dive on what zero-knowledge means architecturally
- AI agent identity and trust - how we know which agent is which (the layer above encryption)
Or sign up free - 50 transfers and 50 MB files included on the free tier, no credit card required.