Skip to content

chore: scan CI logs for secrets before uploading them as artifacts - #2279

Open
nicosampler wants to merge 2 commits into
canton-network:mainfrom
BootNodeDev:nicosampler/1892-ci-scan-secrets-in-logs
Open

chore: scan CI logs for secrets before uploading them as artifacts#2279
nicosampler wants to merge 2 commits into
canton-network:mainfrom
BootNodeDev:nicosampler/1892-ci-scan-secrets-in-logs

Conversation

@nicosampler

Copy link
Copy Markdown

Closes #1892

Why

Artifacts of a public repo can be downloaded by anyone. So a credential printed
into a log is public as soon as the log is uploaded, and deleting the artifact
later does not undo it. Four workflows upload logs today, and nothing checks what
is inside them.

What

New composite action .github/actions/scan_logs_for_secrets runs gitleaks over a
file or directory and fails when it finds something. The six log-upload steps now
depend on it, so a run that leaks stops before publishing instead of after.

  • --redact means a finding reports the file, line and rule, never the value.
  • gitleaks is pinned by version and SHA-256. If the release asset is ever replaced
    upstream, it still gets downloaded but never runs.

Why gitleaks and not the script from the issue

The check the issue points at is two regexes: secret=, token=, private-key=
or password= followed by a value, and JWTs. Copying those two lines would be
easy, but that is all the coverage you get. It has also been deleted from that
repo (canton-network/splice-shared-gha@2282d1c), so there is nothing to reuse.

gitleaks catches those plus GitHub PATs, AWS keys, PEM blocks and Slack webhooks,
with no rules in this repo to maintain.

The two also differ on what happens when something is found. The script hides the
value with sed and uploads the log anyway. This action fails the job and skips
the upload, so the value has to be fixed where it is printed.

Verified

  • The pinned checksum matches the real release asset. All 27 jobs in these
    workflows run on ubuntu-latest, so linux_x64 is the right build.
  • Clean on the six real gateway logs from a recent build.yml run, 60k lines, so
    it should not start failing builds on noise. The gateway already redacts
    ("clientSecret": "*****"); this catches what that misses.
  • Synthetic logs confirm it catches JWTs, GitHub PATs, AWS keys, PEM blocks, Slack
    webhooks and keyword=value assignments.

Still to do

The only way to be sure this works is to plant a secret in a log on purpose, push
that commit, and check that CI turns red, that the error message hides the value,
and that no log artifact shows up on the run. That commit should be reverted once
the test is done. We cannot run this here, so it is up to the reviewer.

Note that stress-tests.yml and examples-under-stress.yml only run on manual
dispatch, so this PR never exercises them.

Limitations

Weak values are not caught. check-logs.sh flags any secret=, token=,
private-key= or password= whatever the value is. gitleaks needs roughly 12
characters and high entropy, so password=hunter2 passes here and would have
failed there.

Lowering the threshold means adding a .gitleaks.toml with an allowlist to keep
current. The reference script needs exactly that, including a sed that hides a
known secret=test. Worth doing if the need shows up.

Playwright reports are not covered. They are still uploaded unscanned, and
their trace files do contain Authorization: Bearer <JWT>. Those are local dev
tokens ({"sub":"ledger-api-user"}, HS256, no exp), so nothing real is exposed
today.

Adding this action to those paths would give a false sense of safety. Playwright
saves its traces as .zip files and gitleaks does not look inside archives. On a
15 MB report it reads only the 2 MB that is not compressed and finds nothing,
while the tokens sit in the zips. Unzipping one by hand turned up 187 JWTs. This
deserves its own issue if these leaks are considered unsafe, or if any of these
jobs could ever run with real credentials.

This fails closed. If the gitleaks download fails, the logs are not uploaded.
Worth knowing when a red run shows no log artifact.

@nicosampler
nicosampler requested a review from a team as a code owner August 12, 2026 17:13
Artifacts of a public repository can be downloaded by anyone, so a
credential printed into a log is public once the log is uploaded.
Deleting the artifact afterwards does not undo that.

Runs gitleaks over a file or directory and fails when it finds
something, with --redact so the finding does not leak the value into the
public job log. gitleaks is pinned by version and SHA-256 so a replaced
release asset is never executed.

Signed-off-by: nicosampler <[email protected]>
Gates the six log-upload steps on the scan having succeeded, so a run
that leaks stops before publishing instead of after.

Signed-off-by: nicosampler <[email protected]>
@nicosampler
nicosampler force-pushed the nicosampler/1892-ci-scan-secrets-in-logs branch from 08af44a to 30f9bbe Compare August 12, 2026 18:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CI to scan for secrets in logs

1 participant