Reference solution
The findings below are ordered by priority.
Findings
1. Lower-priority file values override flags and environment variables
Location: src/load-config.ts:40-45
The spread order applies flags before environment and the project file last. A checked-in endpoint or timeout silently defeats an explicit CI flag, and a file token can replace DEPLOY_TOKEN.
Merge in increasing priority: defaults, validated file settings, validated environment settings, and flags last.
2. The project file is allowed to provide a deployment token
Location: src/config-types.ts:10 and src/load-config.ts:23-27,40-45
ConfigInput includes every CliConfig property, so project-file parsing accepts token and the generic merge uses it. This permits a long-lived credential in a project file even though only a flag or the dedicated environment variable is authorized.
Use distinct types and validation for file, environment, and flag inputs. Reject a file token before resolving any values.
3. The effective cache persists the secret with broad permissions
Location: src/load-config.ts:47-51
The complete resolved object, including token, is serialized to disk with mode 0644. Other local users can read the credential, and it remains after the process exits.
Construct an explicit nonsecret cache payload and write it with mode 0600; never serialize the token.
4. Diagnostics emit the resolved token
Location: src/load-config.ts:52-54
Passing the full configuration as a structured field sends the secret to whichever console, log collector, or CI artifact receives diagnostics. File permissions do not mitigate this separate exposure path.
Log only the names of selected sources or an explicitly redacted summary whose schema cannot contain secret values.
5. Interpolation can read any environment variable and hides missing values
Location: src/load-config.ts:3-19
The regular expression accepts arbitrary names, including unrelated credentials, and replaces an absent variable with an empty string. A malicious or mistaken project file can copy process secrets into ordinary settings, while typos silently produce malformed configuration.
Reject names outside CLI_REGION and CLI_PROFILE, and fail if an allowlisted reference is absent before caching or diagnostics.
6. Tests avoid precedence, interpolation, and every secret sink
Location: src/load-config.test.ts:5-30
The single test supplies only nonsecret file values and checks neither cached contents nor mode. It cannot detect reversed precedence, forbidden token sources, arbitrary interpolation, missing variables, diagnostic leakage, or invalid numeric environment input.
Add a source-precedence matrix and failure cases, then inspect exact cache and diagnostic arguments to prove that a recognizable token never leaves its authorized in-memory field.
Reasonable non-findings
- Reading the project file asynchronously before merging is reasonable.
- Caching effective nonsecret settings is explicitly supported and need not be removed.
- A structured diagnostic event is preferable to string concatenation when its schema excludes secrets.