Skip to content

Linter failure YAML records the full environment, leaking secrets in plaintext #1152

Description

@AndrewDongminYoo

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

  1. export FAKE_SECRET=hunter2 in the shell.
  2. 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.
  3. Open the report path printed under FAILURES.
  4. 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

  1. Redact by default — drop values for variables whose name matches something like TOKEN|SECRET|PASSWORD|PAT|KEY|CREDENTIAL and substitute <redacted>.
  2. Better: record only the variables the linter actually needs (PATH, HOME, LANG, plus whatever the linter definition declares) instead of the whole inherited environment.
  3. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions