Skip to content

[sec-check] Templates silently expand secret env vars ({{GITHUB_TOKEN}}) into AI prompts; builder UI embeds unmasked secrets #46

Description

@hivecommons-hive

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:

  1. Refuse the process.env fallback in autodetect() for sensitive names (variable stays unfilled / falls through to interactive ask).
  2. 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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    agent/securityCreated by Hive for agent-filed issue provenancehelp wantedDenotes an issue that needs help from a contributor. Must meet "help wanted" guidelines.hive/covered-by-prHive verified that an open PR references or claims this issue; still actionable until confirmedsecurityCreated by Hive for agent-filed issue provenance

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions