Skip to main content
· CI/CD · 3 min read

Secure Ephemeral File Transfer in CI/CD Pipelines

In CI/CD pipelines, you often need to move files between stages. You may need to share artifacts with external systems or upload build outputs to a third party. Setting up S3 buckets or NFS shares for temporary file transfer is overkill. Ephemeral CLI-based file sharing fills the gap.

The Problem Space

%%{ init: { 'look': 'handDrawn' } }%%
graph LR
    A[CI Runner<br/>Build complete] -->|1. Package artifact| B[transfer.sh<br/>Generated link]
    B -->|2. Share link<br/>via Slack/Email| C[Reviewer/Tester]
    C -->|3. Download<br/>within 14 days| D[Artifact deleted<br/>automatically]

In a typical pipeline, artifacts need to travel between:

  • Build stage → Test stage → Deploy stage
  • CI runner → External reviewer or QA team
  • Pipeline run → Artifact storage (S3, GCS)

For temporary, one-off file sharing, setting up object storage is operational overhead. A CLI-based approach works in minutes.

Secure File Transfer with transfer.sh

# Upload a file (auto-generates a link)
curl --upload-file ./build.tar.gz https://transfer.sh/build.tar.gz

# Upload with encryption (AES-256)
curl --upload-file <(gzip -c build.tar.gz | openssl enc -aes-256-cbc -pbkdf2) \
  https://transfer.sh/build.tar.gz.gpg

# Upload with auto-expiry (14 days max by default)
# The service handles retention automatically

The service scans for malware, supports Tor hidden service endpoints, and auto-deletes files after the retention period.

CI/CD Integration

# GitHub Actions example
- name: Upload build artifact
  run: |
    ARTIFACT_URL=$(curl --upload-file ./dist.tar.gz https://transfer.sh/dist.tar.gz)
    echo "Artifact: $ARTIFACT_URL"
    # Share via Slack/GitHub PR comment
    echo "::notice file=artifact-url::$ARTIFACT_URL"

- name: Download and verify
  run: |
    curl -o dist.tar.gz https://transfer.sh/abc123/dist.tar.gz
    sha256sum dist.tar.gz

When to Use This vs S3/GCS

ScenarioUse transfer.shUse S3/GCS
Temporary sharing, < 14 days❌ (overkill)
Public artifact, no auth needed
Sensitive data (credentials, keys)⚠️ encrypt first✅ (proper IAM)
Large files (> 5GB)❌ (service limits)
Compliance/audit trail
Programmatic access from pipeline

For sensitive files in CI, always encrypt before uploading:

# Encrypt with a shared secret
ENCRYPTION_KEY=$((head -c 32 /dev/urandom | base64))
echo $ENCRYPTION_KEY >> .encryption_key  # Store in CI secret

tar -czf - ./dist | openssl enc -aes-256-cbc -pbkdf2 -pass pass:$ENCRYPTION_KEY \
  -out dist.tar.gz.enc

curl --upload-file ./dist.tar.gz.enc https://transfer.sh/dist.tar.gz.enc

Decrypt on the receiving end with the same key.

Artifact Expiry in GitOps Context

%%{ init: { 'look': 'handDrawn' } }%%
graph LR
    A[Artifact generated<br/>in CI] --> B[Upload to transfer.sh<br/>14-day expiry]
    B --> C[Link shared in PR]
    C --> D[Reviewer downloads]
    D --> E{Approved?}
    E -->|Yes| F[Artifact uploaded<br/>to S3 permanent storage]
    E -->|No| G[Link expires<br/>artifact auto-deleted]
    F --> H[Deploy to staging/prod]

For GitOps workflows, the ephemeral link serves as a temporary preview mechanism. Approved artifacts get promoted to permanent storage; rejected ones simply expire.

Security Considerations

  • No authentication on the link — anyone with the URL can download
  • Links are guessable but not enumerable — use long random IDs
  • No audit log — you won’t know who downloaded what
  • Encryption is your responsibility — encrypt sensitive files before upload

For anything involving credentials, PII, or compliance requirements, use object storage with proper IAM. For temporary build artifacts, test results, and non-sensitive logs shared during code review, ephemeral transfer is the right tool.