Encrypted secret sharing for GitHub Actions
Create and retrieve self-destructing secret links in CI/CD workflows — with two lines of YAML.
- uses: vaulted-fyi/share-secret@v1
id: share
with:
secret: ${{ secrets.API_KEY }}
views: 1
expires: 24h- uses: vaulted-fyi/share-secret/get@v1
id: get
with:
url: ${{ needs.share.outputs.url }}
- run: echo "Secret is $SECRET"
env:
SECRET: ${{ steps.get.outputs.secret }}End-to-end encrypted
AES-256-GCM encryption happens inside the GitHub Actions runner. Zero-knowledge architecture — the server never sees plaintext or keys. The decryption key lives only in the URL fragment.
Automatic log masking
Calls core.setSecret before setOutput so the decrypted value never appears in workflow logs. Multi-line secrets are masked per-line for complete protection.
No infrastructure needed
No Vault server, no AWS Secrets Manager, no config files. Just two lines of YAML in your workflow and you have encrypted secret sharing.
Composable outputs
The create action outputs both url and id. Compose with Slack notifications, PR comments, email actions, or any step that accepts a string input.
Passphrase protection
Add an optional passphrase for a second factor. The encryption key is wrapped with PBKDF2 — even if someone intercepts the link, they can't decrypt without the passphrase.
Self-destructing links
Set view limits from 1 to 10 views. Set expiration from 1 hour to 30 days. Secrets are automatically deleted from the server when limits are reached.
Common workflows
- uses: vaulted-fyi/share-secret@v1
id: share
with:
secret: ${{ secrets.DEPLOY_TOKEN }}
views: 1
expires: 1h
- uses: actions/github-script@v7
with:
script: |
github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: `Deploy token: ${{ steps.share.outputs.url }}`
})- uses: vaulted-fyi/share-secret@v1
id: share
with:
secret: ${{ secrets.DATABASE_URL }}
views: 3
expires: 7d
- uses: slackapi/slack-github-action@v2
with:
webhook: ${{ secrets.SLACK_WEBHOOK }}
webhook-type: incoming-webhook
payload: |
{"text": "DB credentials: ${{ steps.share.outputs.url }}"}- uses: vaulted-fyi/share-secret@v1
id: share
with:
secret: ${{ secrets.PROD_KEY }}
passphrase: ${{ secrets.SHARE_PASSPHRASE }}
views: 1
expires: 1hCreate inputs
| Input | Required | Default | Description |
|---|---|---|---|
| secret | yes | — | The plaintext secret to encrypt and share |
| views | no | 1 | Max views before auto-delete (1, 3, 5, 10) |
| expires | no | 24h | Expiration time (1h, 24h, 7d, 30d) |
| passphrase | no | — | Optional passphrase for extra protection |
Get inputs
| Input | Required | Default | Description |
|---|---|---|---|
| url | yes | — | Vaulted URL to decrypt |
| passphrase | no | — | Passphrase if the secret is protected |