Repository navigation
fix(zcode): read ZCode 3.18's vault-encrypted credentials on Windows - #1161
Lucentio-Huang wants to merge 3 commits into
Conversation
ZCode 3.18 encrypts ~/.zcode/v2/credentials.json with a key kept in the OS vault instead of the machine user: values read enc:v2:<vault>:<fingerprint>:<iv>.<tag>.<data>, the fingerprint being sha256(key)'s first 24 hex. decrypt knew only v1, so on Windows an account signed in "as ZCode" read nothing and magpie said ZCode isn't signed in on this computer. decrypt hands an enc:v2 value to decryptV2, which on Windows reads the vault through PowerShell's CredRead - a generic credential named after the sha256 of the credentials.json path, whose blob is the 43-char base64url key as UTF-16LE - and remembers a hit per fingerprint (a miss for five minutes, then one more try). The spawn gets an absolute powershell path and its own minimal env, as magpie's plugin host runs with a sanitized env PowerShell starts without. A failed read is noted in the temp folder's zcode-vault-debug.log, without any credential material. ZCODE_CREDENTIAL_V2_SECRET (43 base64url chars) stands in for the vault, as ZCODE_CREDENTIAL_SECRET does for the machine user, and answers enc:v2:env:, which the new vault tests use. macOS keeps its key in the Keychain, which magpie-community#1116 covers.
|
Thanks @Lucentio-Huang, the write-up is clear. This one reads a key out of the Windows Credential Manager (PowerShell CredRead) and writes a debug log to the temp folder, so under this repo's rules it waits for the maintainer to look at it before a full review and merge. I'll come back to it with a run on a Windows box once that's done. |
|
Review, before this merges: the vault read runs a script that can be someone else's.
Please don't run a script from a fixed path. Either pass it inline (
The rest looks fine: it reads only ZCode's own Credential Manager item (CredRead on the sha256-of-path target), checks the fingerprint before using a key, and sends nothing over the network. |
The review is right about the fixed path: readVaultKey wrote the PowerShell to tmpdir() and ran it from there when it existed, and tmpdir() falls back to C:\Windows\Temp when the host env has no TEMP/TMP, where a file another account planted runs as this user and gets the key; and a changed script kept running the old bytes. The script now goes into a fresh mkdtempSync folder each read and the folder is deleted after, so nothing planted is picked up and nothing stale runs; the target stays data (-Target). PowerShell's own temp files land in that same folder, not C:\Windows\Temp. The debug log moves beside the plugin, out of the shared temp folder: it holds no key material, but it names when a vault read failed, so it stays in the user's own profile.
|
All three points addressed in 24b1d52:
|
|
Thanks @Lucentio-Huang, the new head (24b1d52) is noted. As said above, this one reads a credential out of Credential Manager, so it waits for the maintainer to look before I go further or merge. Nothing more needed from you for now. |
|
Ran this branch on a Windows 11 box (ZCode 3.18.2 signed in, magpie 0.1.4179, this branch's
Repro on a Windows box, from a checkout of this branch:
Happy to re-run anything else on the box. |
eb42bf4 to
745377b
Compare
ZCode 3.18 encrypts
~/.zcode/v2/credentials.jsonwith a key kept in the OS vault instead of the machine user: values now readenc:v2:<vault>:<fingerprint>:<iv>.<tag>.<data>where 3.17 and earlier readenc:v1:<iv>.<tag>.<data>, the fingerprint being sha256(key) as 24 hex.decryptknew only v1, so on Windows an account signed in "as ZCode" read no jwt at all, magpie saying the sign-in has no ZCode session ("ZCode isn't signed in on this computer").decryptnow hands anenc:v2value todecryptV2, which on Windows reads the vault through PowerShell's CredRead:powershell.exepath and its own minimal env, as magpie's plugin host runs with a sanitized env (no PATH, no SystemRoot), and PowerShell starts with neitherzcode-vault-debug.log, without any credential material, so a vault that misbehaves in the host env says whyZCODE_CREDENTIAL_V2_SECRET(43 base64url chars, checked strictly as ZCode checks its own) stands in for the vault, asZCODE_CREDENTIAL_SECRETdoes for the machine user, and answersenc:v2:env:— which the new vault tests use, so they run on any platform. A v1 value and a v2 one in one store read side by side.This covers Windows alone; 3.18 on macOS keeps its key in the Keychain, which #1116 covers — the two should be reconciled when that lands.
Per the repo's credential-handling rule: the read touches only ZCode's own vault item on the user's machine, nothing leaves it, and no credential material is written anywhere (the debug log names no key and no value).
Tested on Windows 11, ZCode 3.18.2, magpie 0.1.4179: "ZCode app's sign-in" reads the vault and signs in, the plan windows show, and a request serves.
bun test packages/zcodepasses (274).