Security Finding
Severity: high
Type: unsafe-pattern / secret-exposure
autodetect() (src/autodetect.ts:50-55) falls back to process.env[varName] for ANY template variable name it doesn't recognize. Template resolution (src/resolver.ts, step 2 "Auto-detect") consults this fallback silently, before defaults and before interactive ask — the user is never prompted and never shown the substituted value's origin.
Project-level templates live in .prompts/ checked into the repo (src/loader.ts:11, README). So anyone who can commit a template to a repo you clone controls variable names that expand from your environment.
Reproduction (verified on main @ b922f25):
mkdir -p .prompts
printf 'Summarize the repo. {{GITHUB_TOKEN}}\n' > .prompts/innocent.md
GITHUB_TOKEN=ghp_FAKE promptargs innocent --no-interactive
# → "Summarize the repo. ghp_FAKE"
The same predicate gap exists in the builder UI: collectEnvVars() (src/ui.ts:41-59) embeds every env var not in the cosmetic skip lists into the served page, truncated at 80 chars — full GitHub tokens (~40 chars), AWS keys, and API keys survive intact. shouldSkipEnv('GH_TOKEN') and shouldSkipEnv('AWS_SECRET_ACCESS_KEY') both return false (verified).
Impact
promptargs output is, by design, pasted or piped into third-party AI services (Claude, Copilot, ...). A malicious or careless .prompts/*.md template in any cloned repo exfiltrates GITHUB_TOKEN, AWS_SECRET_ACCESS_KEY, OPENAI_API_KEY, etc. into the prompt stream — silently, even with --no-interactive. The builder UI additionally renders those values in the browser page source.
Recommendation
Add a sensitive-name predicate (e.g. isSensitiveEnvName() matching TOKEN/SECRET/PASSWORD/PASSWD/CREDENTIAL/API(_)KEY/ACCESS_KEY/PRIVATE_KEY/AUTH-segment/COOKIE/BEARER, case-insensitive) and:
- Refuse the
process.env fallback in autodetect() for sensitive names (variable stays unfilled / falls through to interactive ask).
- Exclude sensitive names from
collectEnvVars() in the UI.
Explicit --VAR=value flags remain unaffected — only the implicit env fallback is gated.
Filed by sec-check agent (ACMM L4/L5 — hold-gated mode)
🐝 Hive Agent: security | Instance: hosted-available-oke-11-placeholder-r05x | SHA: unknown
— hive: agent=sec-check backend=copilot model=claude-fable-5 copilot=1.0.88
Security Finding
Severity: high
Type: unsafe-pattern / secret-exposure
autodetect()(src/autodetect.ts:50-55) falls back toprocess.env[varName]for ANY template variable name it doesn't recognize. Template resolution (src/resolver.ts, step 2 "Auto-detect") consults this fallback silently, before defaults and before interactive ask — the user is never prompted and never shown the substituted value's origin.Project-level templates live in
.prompts/checked into the repo (src/loader.ts:11, README). So anyone who can commit a template to a repo you clone controls variable names that expand from your environment.Reproduction (verified on main @ b922f25):
The same predicate gap exists in the builder UI:
collectEnvVars()(src/ui.ts:41-59) embeds every env var not in the cosmetic skip lists into the served page, truncated at 80 chars — full GitHub tokens (~40 chars), AWS keys, and API keys survive intact.shouldSkipEnv('GH_TOKEN')andshouldSkipEnv('AWS_SECRET_ACCESS_KEY')both return false (verified).Impact
promptargs output is, by design, pasted or piped into third-party AI services (Claude, Copilot, ...). A malicious or careless
.prompts/*.mdtemplate in any cloned repo exfiltratesGITHUB_TOKEN,AWS_SECRET_ACCESS_KEY,OPENAI_API_KEY, etc. into the prompt stream — silently, even with--no-interactive. The builder UI additionally renders those values in the browser page source.Recommendation
Add a sensitive-name predicate (e.g.
isSensitiveEnvName()matching TOKEN/SECRET/PASSWORD/PASSWD/CREDENTIAL/API(_)KEY/ACCESS_KEY/PRIVATE_KEY/AUTH-segment/COOKIE/BEARER, case-insensitive) and:process.envfallback inautodetect()for sensitive names (variable stays unfilled / falls through to interactive ask).collectEnvVars()in the UI.Explicit
--VAR=valueflags remain unaffected — only the implicit env fallback is gated.Filed by sec-check agent (ACMM L4/L5 — hold-gated mode)
🐝 Hive Agent:
security| Instance:hosted-available-oke-11-placeholder-r05x| SHA:unknown— hive: agent=sec-check backend=copilot model=claude-fable-5 copilot=1.0.88