security(gpg): pipe private key via stdin instead of writing to /tmp#798
Merged
Conversation
importGPGKey() used to write the GPG private key to a fixed, predictable path in os.tmpdir() (typically /tmp/private-key.asc on Linux, a world-readable mode 1777 directory), call gpg --batch --import <path>, and then unlink. This had several hazards: - Co-resident processes on shared runners could read the key between writeFile and unlink. - A symlink planted at /tmp/private-key.asc before writeFile would redirect the write to an attacker-chosen destination. - An unexpected crash between writeFile and unlink would leave the key on disk indefinitely. Pipe the key to gpg via stdin instead. The spawnProcess helper already supports stdin; gpg with --batch --import reads a key from stdin when no file argument is given. Nothing ever touches disk. Key also no longer appears in argv, which improves the process-list visibility profile.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Eliminates the TOCTOU / information-disclosure hazard in
importGPGKey(): the private key is now piped togpg --batch --importvia stdin instead of being written to a fixed, predictable path inos.tmpdir().Motivation
The previous implementation:
On Linux,
/tmpis mode 1777 (world-writable, with the sticky bit). The path is deterministic, so:writeFileandunlink.ln -s /some/target /tmp/private-key.ascbefore thewriteFilecall causes Craft to overwrite/some/targetwith the private key.writeFileandunlinkleaves the key on disk indefinitely.Fix
Pass the key via stdin.
gpg --batch --importreads a key from stdin when no file argument is given.spawnProcessalready supports astdinoption — no new infrastructure needed.Benefits vs.
mkdtemp(0o700)alternative:argveither, so it doesn't show up inps//proc/<pid>/cmdline.Tests
src/utils/__tests__/gpg.test.tsis rewritten to assert the new invariants:spawnProcessis called with['--batch', '--import']and{ stdin: KEY }.fs.writeFile/fs.unlinkhappens.pnpm test src/utils/__tests__/gpg.test.ts→ 3 tests pass. Full lint / build clean.Callers
Only
src/targets/maven.ts:271callsimportGPGKey. The signature is unchanged (importGPGKey(privateKey: string): Promise<void>) — no caller updates needed.