CI security / Runnerless Stories
Accidental CI secret leaks: logs, artifacts, and core dumps
Published
Sources reviewed
A clean console log does not establish that credentials are absent from diagnostic files or process memory. A job can hide a value in its output while saving it in a test report, generated configuration, or crash dump that later becomes an artifact.
On this page
Where credentials can leave a CI job
Start by following the credential through the job: which process receives it, which subprocesses inherit it, and which files those processes write. A publishing command may need authentication. The test suite and report uploader often do not.
Accidental exposure has several routes:
- Debug logging and shell tracing: an SDK prints request headers, or
set -xprints a command after variable expansion. - Transformed values: encoding, splitting, or reformatting a value can stop a literal match from recognizing it.
- Command arguments: credentials passed as arguments can appear in process inspection or diagnostic output, depending on permissions and tooling.
- Generated configuration: authentication written to a package-manager config can be swept into an upload of the working directory.
- Test reports and artifacts: a failure report may contain environment details or captured request data that never appeared in the console.
- Caches: a cached home or configuration directory can preserve authentication material beyond the job that created it.
Original demonstration text: orchard
Console with a literal mask: ***
Text split by a diagnostic: or-chard
Saved diagnostic file: {"example": "orchard"}Masking the console’s exact match changes neither the split text nor the saved file. Actual redaction behavior depends on the CI system and output path.
Logs and saved reports are not the only outputs to inspect. A crash can also turn process memory into a diagnostic file.
How process memory becomes a debugging artifact
A core dump can capture memory from a crashing process. If credentials were loaded through environment variables, configuration, or an SDK, copies may still be in that memory when capture occurs. Clearing one variable does not prove every copy has been erased.
On systems configured with systemd-coredump, the handler processes crash dumps and can store them for later inspection. Capture and retention depend on the host, process limits, and handler configuration. This is not a claim that GitHub-hosted runners or CircleCI executors always capture dumps. Check the executor image, process core limits, and any dump handler configured on the host. systemd’s coredump handling documentation.
The next leak can be a routine debugging step: someone includes the crash file in an artifact upload or support bundle. Console masking does not sanitize the dump’s contents. Decide deliberately whether credential-bearing processes should produce dumps, who can retrieve them, and how long they remain. If capture is necessary, treat the dump as sensitive data rather than a report ready for public download.
A private diagnostic can become a public artifact
A debugging file starts with the access controls of the machine that created it. Uploading it to artifact storage, attaching it to a pull request, or including it in a support bundle gives it a different audience and lifetime. A report intended for the developer who ran a test can become visible to everyone who can follow its link.
The same problem applies to caches. A directory saved for convenience can include generated authentication files as well as dependencies. A later job may restore files that its author did not realize contained credentials.
Inspect the upload rules, not just the files you expect to publish. A pattern that captures the whole workspace can also collect crash dumps, hidden configuration, or reports from failed runs. Verifying a file’s checksum establishes which bytes were transferred; it does not establish that those bytes are free of secrets.
Inspect the files and processes around a failure
Follow one credential through a representative job, including its failure path:
- List the processes that receive the credential and the subprocesses that inherit it. Remove access from test suites and upload steps that do not need it.
- Check SDK debug output and shell tracing. Avoid putting credentials in command arguments that diagnostic tools might record.
- Inspect generated configuration, test reports, and the directories selected for artifact uploads and caches. Prefer explicit file allowlists over whole-workspace uploads.
- Check whether the executor captures process dumps, where they are stored, who can retrieve them, and when they expire. Treat necessary dumps as sensitive diagnostics.
- Review both successful and failed runs. An exception handler may print information that the normal path never logs.
If a credential was exposed, revoke or rotate it as applicable, investigate its access, and remove exposed diagnostics through your incident procedure. A clean rerun does not undo the earlier exposure. GitHub’s secure-use guidance covers auditing secret handling and deleting and rotating exposed secrets.
The companion story, how modern CI protects secrets, explains what masking, access restrictions, trusted publishing, and a proposed isolated publishing service can change.