GitHub Actions automatically redacts secret values from workflow logs. Parsing structured data stored as secrets with fromJSON()
bypasses this protection for the individual field values.
GitHub Actions recognizes secrets by their exact string value and redacts them from logs. When a secret contains structured data (such as a JSON
object) and that data is parsed using fromJSON(), the resulting field values are new strings that GitHub Actions does not recognize as
secrets. These parsed values are therefore not automatically redacted and can appear in workflow logs.
If a workflow logs output containing a parsed secret field — whether intentionally for debugging or because a command echoes its arguments — the sensitive value will appear in plain text in the workflow logs. Log files are often accessible to all repository collaborators and may be stored for extended periods, increasing the window of exposure.
name: Example
on:
pull_request:
jobs:
main:
runs-on: ubuntu-latest
steps:
- name: Example Step
env:
SECRET: ${{ fromJSON(secrets.JSON_SECRET).SECRET_IN_JSON }} # Noncompliant
run: |
example-command "$SECRET"
The example below is compliant because the secret is not parsed from structured data.
name: Example
on:
pull_request:
jobs:
main:
runs-on: ubuntu-latest
steps:
- name: Example Step
env:
SECRET: ${{ secrets.SECRET }}
run: |
example-command "$SECRET"