Audit Logging and Non-Repudiation — Tamper-Evident File Transfer Audit Log
Audit Logging and Non-Repudiation
Section titled “Audit Logging and Non-Repudiation”Xferity maintains a structured audit log that records every significant system event. The audit log is separate from the application log — it is designed for compliance, incident investigation, and non-repudiation.
Enabling audit logging
Section titled “Enabling audit logging”audit: enabled: true path: /var/log/xferity/audit.jsonl retention_days: 365 # prune events older than 365 days strict_redaction: false # see redaction section tamper_evidence_enabled: true # SHA-256 hash chain query_index_enabled: true # fast query index sidecarWhat is recorded
Section titled “What is recorded”Every audit event contains:
| Field | Description |
|---|---|
timestamp | UTC timestamp with nanosecond precision |
level | Event severity (info, warn, error) |
flow_name | Name of the flow that triggered the event |
run_id | Unique identifier for this flow execution |
correlation_id | Correlation ID for linking related events |
event_type | Category of event (see event types below) |
file | Filename being operated on |
remote_path | Remote path on SFTP/FTPS/S3/AS2 |
local_path | Local path on the filesystem |
idempotency_key | SHA-256 hash used for deduplication |
outcome | success, failure, or skipped |
error_code | Machine-readable error code on failure |
error_message | Redacted error description |
metadata | Additional context key-value pairs |
Event types
Section titled “Event types”Xferity emits events for the following operations:
flow_start— a flow execution beginsflow_complete— a flow execution completes successfullyflow_failed— a flow execution fails after all retriesfile_download— a file is downloaded from a remote sourcefile_upload— a file is uploaded to a remote destinationfile_encrypt— a file is PGP encryptedfile_decrypt— a file is PGP decryptedfile_sign— a file is PGP signedfile_verify— a PGP signature is verifiedfile_delete— a file is deleted (local or remote)file_skipped— a file is skipped due to idempotencyas2_receive— an inbound AS2 message is receivedas2_send— an outbound AS2 message is sentas2_mdn— an AS2 MDN is sent or receivedauth_login— a user authenticates (success or failure)auth_logout— a user session ends
Tamper-evident hash chain
Section titled “Tamper-evident hash chain”When tamper_evidence_enabled: true, each audit event is linked to the previous event using a SHA-256 hash chain.
Every event receives three additional fields:
| Field | Description |
|---|---|
chain_seq | Monotonically incrementing sequence number (starts at 1) |
prev_hash | SHA-256 hash of the previous event (empty for the first event) |
event_hash | SHA-256 hash of this event’s canonical JSON + prev_hash |
This creates a cryptographic chain: modifying, inserting, or deleting any audit event breaks the chain and is detectable.
How the chain is computed
Section titled “How the chain is computed”event_hash = SHA-256(prev_hash + "|" + canonical_event_json)Where canonical_event_json is the full event JSON with the event_hash field set to an empty string before hashing.
Verifying the hash chain
Section titled “Verifying the hash chain”Because the audit log is a plain JSONL file, the hash chain can be verified independently using any JSON processing tool. No proprietary tooling is required.
Verification checks:
- Every event has a
chain_seqfield - Sequence numbers are consecutive (no gaps)
- Each
prev_hashmatches theevent_hashof the preceding event - Each
event_hashmatches the recomputed hash
Manual verification
Section titled “Manual verification”# Check that chain_seq values are consecutivejq '.chain_seq' /var/log/xferity/audit.jsonl | awk 'NR>1 && $1!=prev+1{print "BREAK at seq ",$1}{prev=$1}'You can also recompute event hashes from the stored canonical JSON to confirm no event was altered.
Audit log format
Section titled “Audit log format”The audit log is JSONL (one JSON object per line). Example:
{"timestamp":"2026-03-16T22:00:01.234567Z","level":"info","flow_name":"payroll-upload","run_id":"run-abc123","correlation_id":"corr-xyz789","event_type":"file_upload","file":"payroll-2026-03.xml","remote_path":"/outgoing/payroll/payroll-2026-03.xml.pgp","outcome":"success","idempotency_key":"sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","chain_seq":42,"prev_hash":"a1b2c3...","event_hash":"d4e5f6..."}Redaction
Section titled “Redaction”Sensitive values are automatically redacted from audit events. Fields containing keywords such as password, passphrase, private_key, token, secret, api_key are replaced with [REDACTED] before writing.
Strict redaction mode
Section titled “Strict redaction mode”When strict_redaction: true, additional patterns are redacted:
- Email addresses
- Bearer tokens and JWT patterns
- File paths (Unix and Windows)
- PEM private key blocks
- API key patterns
- Passphrase fields
Use strict redaction in regulated environments where even metadata must be protected.
audit: strict_redaction: trueAudit query index
Section titled “Audit query index”When query_index_enabled: true (default), Xferity maintains a sidecar index file (audit.jsonl.idx.jsonl) that enables fast queries without scanning the full audit log.
Query by flow, event type, file name, outcome, or time range:
# Query audit for a specific flowxferity trace --flow payroll-upload
# Query for a specific filexferity trace --file payroll-2026-03.xml
# Query for failures in the last 24 hoursxferity trace --outcome failure --since 24hRetention
Section titled “Retention”Xferity automatically prunes audit events older than retention_days:
audit: retention_days: 365Retention runs at startup and periodically during execution. When retention runs:
- Events older than the cutoff are removed
- The chain state is reset (the chain restarts after pruning)
- Malformed lines are preserved to prevent accidental data loss
Set retention_days: 0 or omit to keep all events indefinitely.
On-disk structure
Section titled “On-disk structure”Given audit.path: /var/log/xferity/audit.jsonl, Xferity creates:
| File | Description |
|---|---|
audit.jsonl | Main audit log (one JSON event per line) |
audit.jsonl.chain.state | Current chain head (seq + hash for continuity across restarts) |
audit.jsonl.idx.jsonl | Query index sidecar (when query_index_enabled: true) |
Back up all three files together. The .chain.state file is required for chain continuity after restart.
Compliance-relevant characteristics
Section titled “Compliance-relevant characteristics”The audit log structure provides characteristics relevant to regulated environments:
- Transfer record completeness: every file movement, encryption, decryption, and authentication event is recorded with timestamp and outcome
- Tamper evidence: the SHA-256 hash chain detects modification, deletion, or insertion of events
- Redaction controls: sensitive field values are excluded from the log; strict redaction mode is available for environments with stricter metadata requirements
- Retention controls: configurable retention period with automatic pruning
Organizations working toward SOX, HIPAA, or PCI-DSS requirements typically need a complete file transfer audit record. Xferity provides that record. Whether the audit log satisfies specific regulatory requirements depends on your overall compliance architecture, not on a single component.