What is a GitHub Actions secret?
A secret is a sensitive value—such as an API key, deployment credential or password—that a workflow can read when it runs. Instead of committing the value to a repository, you save it in GitHub’s Actions secrets settings and reference it in the workflow. GitHub supports secrets at repository, environment and organization levels; choose the narrowest scope that fits the job.
Secrets are not a substitute for good workflow design. A workflow that can access a key can use it, and code running in that job may be able to send it elsewhere. Give each credential only the access it needs, and avoid exposing it to jobs that do not need it.
1. Create a repository secret
- Open the repository on GitHub and select Settings.
- Choose Secrets and variables, then Actions.
- Select New repository secret.
- Use a clear name such as
DEMO_API_KEY, paste the value from the provider, then save it.
Use a test key with limited permissions when learning. Do not paste a real production key into an issue, chat, workflow YAML, source file, command-line argument or screenshot. For deploy credentials used only in production, consider an environment secret and add environment protection or required approval where your plan and workflow allow it.
2. Pass the value to only the step that needs it
This small workflow runs manually. It grants the built-in GITHUB_TOKEN read-only access to repository contents and exposes the example API key only to one step. The check confirms the variable exists but never prints its value.
name: Secret handling example
on:
workflow_dispatch:
permissions:
contents: read
jobs:
check-secret:
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Confirm the key is available without printing it
env:
API_KEY: ${{ secrets.DEMO_API_KEY }}
run: |
node <<'NODE'
if (!process.env.API_KEY) process.exit(1);
console.log('API key is available; value not displayed');
NODE
On a narrow screen, swipe horizontally inside the code box to inspect any line that does not fit.
Replace the final check with your application’s real command. In your code, read the value from the process environment (for example, process.env.API_KEY) and pass it to the client library without logging it. Do not write the secret into a generated file that is uploaded as an artifact.
The action reference uses a version tag for readability. For higher supply-chain assurance, review third-party actions and pin them to a verified full commit SHA, updating that SHA deliberately. The example also avoids granting write access: add a specific permissions entry only if a workflow genuinely needs it.
3. Keep secrets out of logs and source history
Never print a secret for debugging, even if GitHub usually masks registered secret values in logs. GitHub warns that automatic redaction is not guaranteed, especially when a value is transformed, encoded or embedded in structured data. Do not rely on masking as your security boundary. Avoid commands such as echo "$API_KEY", verbose debug output that might include request headers, or dumping the process environment.
Keep local development secrets in an ignored file such as .env.local, and commit only a safe example such as .env.example with blank values. Check that secret-bearing files are ignored before committing. If a secret has ever been committed, deleting it in a later commit does not make the exposed value safe again; revoke or rotate it with the provider.
4. Understand pull request and environment boundaries
For security, GitHub does not pass ordinary repository secrets to workflows triggered by pull requests from forks. The built-in GITHUB_TOKEN is an exception with restricted permissions. Do not try to bypass this by switching to pull_request_target and then checking out or executing untrusted pull-request code: GitHub warns that privileged workflows combined with untrusted code can expose secrets and write-capable tokens.
For trusted deployment workflows, environment secrets can add a separate boundary. Configure a named environment, restrict which branches can deploy, and require a reviewer where appropriate. A job cannot use protected environment secrets until its protection rules are satisfied. For cloud deployments, check whether your provider supports OpenID Connect (OIDC): it can exchange a short-lived credential for a specific workflow rather than storing a long-lived cloud key in GitHub.
5. Set the least permissions the workflow needs
GITHUB_TOKEN is created for a workflow run, but its permissions still matter. Declare a minimal top-level permission set, as in the example, then add narrowly scoped permissions to a specific job only when required. An action may be able to access the token through GitHub’s token context even if you do not explicitly pass it, so review every action used in a privileged job.
If an API key leaks
- Revoke or rotate it at the provider immediately. Removing the string from the latest source file is not enough.
- Check the credential’s activity and scope. Look for unexpected use, then reduce permissions on the replacement key.
- Review Actions logs, artifacts and workflow permissions. If a log reveals the value, restrict access and delete the affected log where GitHub allows it.
- Search the repository history and any copies. Remove the exposed value from code and follow GitHub’s guidance if history cleanup is needed; coordinate with collaborators before rewriting history.
- Store the replacement as a secret and test the workflow without printing it.
Assume a credential is compromised as soon as it appears in a public repository or an accessible log. Rotation is the important containment step; masking or deleting the visible text alone does not invalidate the old key.
Quick checklist
- Store credentials in GitHub Actions secrets, not in committed files.
- Use a descriptive secret name and the smallest useful scope.
- Expose a secret only to the job or step that needs it.
- Set explicit minimum
GITHUB_TOKENpermissions. - Do not print secrets; do not trust log masking to catch every transformed value.
- Do not run untrusted pull-request code with privileged secrets.
- Rotate a leaked key immediately, then review logs, artifacts and access.
Frequently asked questions
Can I use a secret in a GitHub Actions workflow?
Yes. Create it in the repository, environment or organization Actions settings, then reference it with the secrets context. Pass it through an environment variable to the step that needs it and avoid logging its value.
Why is a secret empty in a workflow from a fork?
GitHub withholds ordinary secrets from workflows triggered by forked pull requests to protect the repository owner. Keep untrusted fork code unprivileged; do not switch to a privileged event and execute the untrusted code to make the secret available.
Does GitHub masking make a secret safe if I print it?
No. GitHub notes that redaction can fail when the secret is transformed or formatted differently. Treat logs as a place where secrets must never be written.
Should cloud credentials be stored as GitHub secrets?
Sometimes a provider requires a stored credential, but first check whether OIDC is supported. OIDC can let a workflow obtain short-lived cloud credentials under a trust policy, reducing reliance on long-lived keys.
Official references
Continue with developer guides
This is the first guide in Inkech’s GitHub and developer-tools section. Explore the collection for practical tutorials on secure workflows, GitHub integrations and AI coding tools.