Filing here because there is no public repository for the CLI itself — happy to move this if there is a better venue.
Summary
When a linter exits non-zero, trunk check writes a failure report to $TRUNK_CACHE/repos/<hash>/out/<id>.yaml. That report contains a rerun: field built as env -i <every environment variable> <command>, so every environment variable present at invocation is serialized verbatim — including credentials.
Values I found in a single report on an ordinary developer machine:
GITHUB_PERSONAL_ACCESS_TOKEN=gho_…
NPM_TOKEN=npm_…
VSCE_PAT=…
Anything else exported in the shell (cloud keys, CI tokens, *_API_KEY) lands there the same way.
Version
trunk_cli_version: 1.25.0
TRUNK_LAUNCHER_VERSION: 1.3.4
macOS, darwin-arm64.
Reproduction
export FAKE_SECRET=hunter2 in the shell.
- Trigger any linter failure. A reliable one: run
trunk check <file> inside a git submodule, where git-diff-check exits 128 with fatal: not a git repository: …/.git/modules/<name> because the linter runs from a temp sandbox that cannot resolve the submodule's gitdir.
- Open the report path printed under
FAILURES.
FAKE_SECRET=hunter2 appears in the rerun: line.
Why this matters
- The
NOTICES block tells the user "A tool failed to run. You can open the details yaml file for more information." That invites pasting or attaching the file when reporting a problem — so the secrets travel with it, and nothing in the file signals that it contains credentials.
- The reports persist on disk with no expiry, and the cache directory is not gitignored in every setup.
Suggested fixes
- Redact by default — drop values for variables whose name matches something like
TOKEN|SECRET|PASSWORD|PAT|KEY|CREDENTIAL and substitute <redacted>.
- Better: record only the variables the linter actually needs (
PATH, HOME, LANG, plus whatever the linter definition declares) instead of the whole inherited environment.
- Print a note next to the report path when anything was redacted, so the user knows the
rerun: line needs their own secrets re-supplied.
Separate, smaller bug
git-diff-check fails with exit 128 inside a git submodule: the sandbox copy at /tmp/trunk-<uid>/<id> has the submodule's .git file pointing at ../.git/modules/<name>, which does not resolve relative to the sandbox. Happy to split this into its own issue.
Filing here because there is no public repository for the CLI itself — happy to move this if there is a better venue.
Summary
When a linter exits non-zero,
trunk checkwrites a failure report to$TRUNK_CACHE/repos/<hash>/out/<id>.yaml. That report contains arerun:field built asenv -i <every environment variable> <command>, so every environment variable present at invocation is serialized verbatim — including credentials.Values I found in a single report on an ordinary developer machine:
GITHUB_PERSONAL_ACCESS_TOKEN=gho_…NPM_TOKEN=npm_…VSCE_PAT=…Anything else exported in the shell (cloud keys, CI tokens,
*_API_KEY) lands there the same way.Version
macOS, darwin-arm64.
Reproduction
export FAKE_SECRET=hunter2in the shell.trunk check <file>inside a git submodule, wheregit-diff-checkexits 128 withfatal: not a git repository: …/.git/modules/<name>because the linter runs from a temp sandbox that cannot resolve the submodule's gitdir.FAILURES.FAKE_SECRET=hunter2appears in thererun:line.Why this matters
NOTICESblock tells the user "A tool failed to run. You can open the details yaml file for more information." That invites pasting or attaching the file when reporting a problem — so the secrets travel with it, and nothing in the file signals that it contains credentials.Suggested fixes
TOKEN|SECRET|PASSWORD|PAT|KEY|CREDENTIALand substitute<redacted>.PATH,HOME,LANG, plus whatever the linter definition declares) instead of the whole inherited environment.rerun:line needs their own secrets re-supplied.Separate, smaller bug
git-diff-checkfails with exit 128 inside a git submodule: the sandbox copy at/tmp/trunk-<uid>/<id>has the submodule's.gitfile pointing at../.git/modules/<name>, which does not resolve relative to the sandbox. Happy to split this into its own issue.