Skip to content

Security: installation token passed via named 'Token' input may leak in debug logs #103

Description

Summary

When PSModule/GitHub-Script is called with an explicit Token: input (e.g. a GitHub App installation token minted by actions/create-github-app-token), the token value is passed as a named action with: input. This introduces two potential leak vectors compared to passing it only as an environment variable.

Risk level

Medium

Leak vectors

1. Debug log exposure

When ACTIONS_STEP_DEBUG=true (enabled by any repo/org admin, or automatically by some third-party integrations), GitHub Actions logs ##[debug] Input name: TOKEN entries that can include the input value. While actions/create-github-app-token calls core.setSecret() for the token, GitHub's runner-level masking has known gaps:

  • Values split across log lines may not be masked
  • URL-encoded or base64-encoded forms of the token are not masked automatically

2. result output reflection

PSModule/GitHub-Script returns a result step output. If the action reflects its inputs into the result JSON (common in GitHub Script wrappers), any downstream step reading steps.<id>.outputs.result could access the token value.

Current usage in Process-PSModule

Get-PSModuleSettings/action.yml passes a GitHub App installation token via both channels:

- uses: PSModule/GitHub-Script@8083ec1f733f00357ee4d0db0c6056686e483bc0
  env:
    GH_TOKEN: ${{ env.GH_TOKEN }}     # safe: env var, picked up by gh CLI
  with:
    Token: ${{ env.GH_TOKEN }}        # risk: named input

The env: GH_TOKEN channel is sufficient for gh CLI calls and is the recommended pattern. The with: Token: channel is needed only if the action internally calls core.getInput('token') to pass it to an API client.

Suggested fixes

Option A (preferred) - read token from environment only:
If PSModule/GitHub-Script can be updated to read GH_TOKEN (or GITHUB_TOKEN) from the environment instead of requiring a named Token: input, callers can drop the with: Token: line entirely. This is already how the gh CLI works and avoids the input-leak surface completely.

Option B - mask the token explicitly at entry:
If the named Token: input must remain, call core.setSecret(core.getInput('token')) as the very first line of the action's entrypoint (before any logging or debug output). This ensures masking is applied before the Actions runner emits any debug lines for this step.

Option C - document the risk:
If neither change is feasible, document that callers using sensitive tokens (e.g. GitHub App installation tokens) should not enable ACTIONS_STEP_DEBUG while this action is in use, and that the result output should not be logged or exposed to untrusted steps.

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions