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.

Why is this an issue?

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.

What is the potential impact?

Sensitive data exposure in 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.

How to fix it

Code examples

Noncompliant code example

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"

Compliant solution

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"

Resources

Documentation

Standards