The audit asked 'who received this file' and the logs couldn't say

The SFTP server records every connection: source IP, username, timestamp, session duration. The compliance lead points at the folder and calls it the audit trail. It is a doorbell log. It proves someone rang, and nothing about what they carried, who took it, or whether it arrived intact.

That gap stays invisible until an auditor stops asking about controls in the abstract and puts a finger on one row in a spreadsheet: this payment instruction, this patient record, this bordereau. Show me its chain of custody. The single sampled transaction is where connection logging falls apart.

Connection logs versus per-transfer chain-of-custody records

A connection log answers a thin question: did a session happen. A custody record answers a sharper one: what happened to this file. Most home-grown setups only manage the first, because that is what the daemon writes for free. A nightly cron that runs sftp partner@host and put /outbound/*.csv leaves an auth line in /var/log and an exit code. Nothing ties those bytes to a file hash, a named recipient, a delivery state, or a retry.

The custody record an auditor wants follows a shape long settled in digital evidence handling: who held the item, when, what moved, and where it went. Map that onto a file and the minimum row is not negotiable:

What evidence means when an auditor samples one transaction

Auditors do not read the whole log. They sample. A control that produces the sampled item is presumed to work across the population; one that cannot is presumed broken everywhere. You do not need near-total coverage to pass, only the one row they picked, reconstructed end to end.

Connection logs fail this because they are not keyed on the file. The auditor names a file, you grep the access log, and you find forty sessions from that night, any of which could have carried it. You cannot say which. "We believe it went out overnight" is not evidence. Evidence names the file, hashes it, names the recipient, and states the outcome, all retrievable by the same identifier the auditor used to ask.

Non-repudiation: signed receipts and delivery confirmation

Even a clean per-file send log has a hole: it is your word. You wrote delivered; the partner can claim nothing arrived, and a sender-side record alone cannot refute them. Non-repudiation closes the hole by making the receipt come from the receiver and binding it cryptographically to the payload. This is why regulated supply chains mandate AS2 over plain SFTP. Under RFC 4130, the receiver returns a signed Message Disposition Notification whose MIC is computed over the payload it received. An MDN matching your hash is third-party-verifiable proof of receipt, not a hopeful log line, and it removes the failure chain-of-custody design exists to rule out: a counterparty quietly disowning the data.

Logging that survives an evidence request

Build the record at the transfer layer, not by scraping daemon logs after the fact. Each transfer emits one immutable event keyed on a file identifier, carrying the hash, both parties, the protocol, and the final outcome including failures and retries. Make it queryable by file, recipient, and time, because that is how the request arrives. Capture the receiver's confirmation, signed wherever the protocol supports it, so delivered is something you prove rather than assert.

xEvolve writes that per-transfer custody record automatically for every file in your Environment, across SFTP and AS2 alike, hash and signed receipt included. When the auditor names one transaction, you answer with the file, the recipient, and the outcome, not a session that might have been the one. See how the audit trail is built.