GitHub Secret Scanning for Actions Workflow Logs: Separate Print-Time Masking (::add-mask::) from Post-Run Scanning Blind Spots
Understand how GitHub's new secret scanning for Actions workflow logs (public preview) complements print-time ::add-mask:: redaction, and account for its 5 preview limitations including custom-pattern and notification blind spots.
A conceptual illustration showing Stage 1 print-time redaction (::add-mask::) alongside Stage 2 post-run workflow log secret scanning for provider patterns and persistent alert storage. This is not an actual console screenshot.
On November 9, 2026, GitHub launched a public preview of secret scanning for GitHub Actions workflow logs, extending secret detection beyond repository code, issues, wikis, discussions, and pull requests into CI/CD console output. Whenever a workflow run completes, GitHub scans the finished logs for supported provider patterns, runs validity checks on matching credentials, and records findings in the repository's secret scanning alert list—preserving the alert even after the workflow logs themselves are deleted. GitHub Changelog Announcement, GitHub Enterprise Cloud Policy Docs
The core operational takeaway: post-run workflow log scanning is a safety net for unmasked provider tokens, not a replacement for print-time masking (::add-mask::), and it carries five critical preview limitations. During the public preview, the scanner (1) ignores generic patterns, custom enterprise regexes, and AI-detected secrets, (2) does not backfill existing workflow logs completed before activation, and (3) does not send email or webhook notifications when a log leak is found. Teams must combine strict print-time masking (“mask first, export second”) with direct polling of their secret scanning alert list.
This guide analyzes the boundary between runtime redaction and post-run log scanning, the five preview blind spots, and safe dynamic-token workflow patterns based on the GitHub Changelog post, the GitHub Enterprise policy documentation, and community security analyses (DEV Community, C# Corner). It does not inject live credentials into production GitHub Enterprise Cloud tenants; the local Python checks below model print-time masking order and post-run scanner coverage.
1. Why Secrets Still Leak Despite GitHub Actions Runtime Redaction (***)
The GitHub Actions runner redacts registered repository, environment, and organization secrets (secrets.*) as well as values passed to ::add-mask:: by replacing exact string matches with *** at print time. Leaks still reach saved workflow logs whenever a secret is dynamically minted or transformed before the runner knows to mask it:
| Dimension | Stage 1: Runner Print-Time Redaction ( ***) | Stage 2: Post-Run Workflow Log Secret Scanning (Public Preview) |
| Execution Timing | Inline while the step is streaming standard output and standard error | After the workflow run completes, scanning the persisted log output |
| Matching Mechanism | Exact substring match against pre-registered secrets.* values and strings registered via ::add-mask:: | Scans unmasked log text for supported provider patterns and executes partner validity checks |
| Common Blind Spots | Dynamically minted OAuth/cloud tokens printed before ::add-mask::, sliced/encoded strings, full JSON responses echoed by CLI tools, or commands run under set -x | Generic patterns, custom regex patterns, AI-detected secrets, and historical logs completed prior to enabling the policy (already-masked *** strings are also skipped) |
| Blast Radius & Log Deletion Behavior | Prevents the secret from ever reaching stored logs or log viewers | Anyone with read access to Actions logs can view the secret until the log is deleted; deleting the log does not close or delete the secret scanning alert |
Keeping the alert open after log deletion is intentional: because read access to Actions logs is typically granted to a much broader group than secret administration, a deleted log is not a rotated credential.
2. Enablement Requirements and the Five Public Preview Limitations
Enabling workflow log scanning requires no changes to .github/workflows/*.yml, but enterprise administrators and security teams must account for five operational constraints:
| Requirement / Constraint | Supported Scope & Configuration | Operational Impact During Public Preview |
| 1. Plan & Licensing | GitHub Enterprise Cloud (including data residency on GHE.com) with GitHub Secret Protection or GitHub Advanced Security (GHAS) | Disabled by default. Applies only to repositories within the enterprise that already have secret scanning enabled |
| 2. Policy Path | Enterprise Settings → Policies → Advanced Security → Secret scanning for Actions workflow logs → Enabled (under All repositories) | Configured at the enterprise policy level by an enterprise owner rather than per workflow file |
| 3. No Historical Backfill | Scans only workflow runs that complete after the enterprise policy is enabled | Existing workflow logs from earlier runs are never retroactively scanned |
| 4. Provider Patterns Only | Detects identifiable partner/provider token formats (and runs validity checks where supported) | Does not detect generic secrets, custom enterprise/org patterns, or AI-detected secrets in workflow logs |
| 5. Zero Alert Notifications | Findings appear in the repository's Security → Secret scanning alerts list with a deep link to the workflow log | Alerts from workflow logs do not trigger email or webhook notifications during the preview. Teams must inspect the alert list or poll the REST API directly |
3. Safe Workflow Patterns: “Mask First, Export Second”
Because custom internal tokens and generic passwords are not covered by the post-run log scanner—and because even provider tokens remain readable to log viewers until rotated—every workflow step that mints a dynamic credential must register ::add-mask:: before any command can print or export it:
To compensate for the lack of automatic notifications during the public preview, schedule a lightweight check using the GitHub CLI (gh api) to surface open secret scanning alerts across your repositories:
4. Modeling Print-Time Masking vs. Post-Run Log Scanning in Python
The dependency-free Python script below models the two-stage pipeline—showing how ordering ::add-mask:: before output prevents alerts entirely, while custom internal tokens and historical runs bypass the post-run workflow log scanner.
Scope Verified Locally
Running this simulation in a local Python environment verified four boundary scenarios:
- Provider token printed before
::add-mask::: Leaks intorendered_log[0]and triggers agithub_patalert at the end of the run withnotification_sent: Falseandpersists_after_log_deletion: True.
- Provider token masked via
::add-mask::before printing: Redacted toecho 'Token: ***'at print time, producing0post-run alerts.
- Unmasked custom internal token (
INTERNAL_TOKEN_...): Leaves0post-run alerts because workflow log scanning excludes custom, generic, and AI-detected patterns.
- Historical workflow run (
is_historical_run=True): Produces0alerts because existing logs are not backfilled when the policy is enabled.
5. Rollout and SecOps Checklist
- Enable the enterprise policy explicitly: Turn on Secret scanning for Actions workflow logs under Enterprise Settings → Policies → Advanced Security, and verify that target repositories have secret scanning enabled.
- Poll the secret scanning alerts list or API directly: Because workflow log alerts do not generate notifications during public preview, integrate alert polling into your security triage workflow.
- Prefer OIDC and pre-output
::add-mask::for dynamic credentials: Use official OIDC actions (which automatically register masks before exporting tokens) and audit shell steps forprintenv,set -x, or unmasked custom tokens that post-run log scanning will not catch.
References
Last verified: November 11, 2026
Korean version:
GitHub Actions 워크플로 로그 시크릿 스캐닝 해부: 런타임 마스킹(::add-mask::)과 사후 스캔의 5가지 사각지대 점검하기