Skip to content

fix(onboard): prevent API key plaintext exposure in retry prompt#1313

Merged
ericksoa merged 6 commits into
NVIDIA:mainfrom
BenediktSchackenberg:fix/api-key-retry-plaintext
Apr 14, 2026
Merged

fix(onboard): prevent API key plaintext exposure in retry prompt#1313
ericksoa merged 6 commits into
NVIDIA:mainfrom
BenediktSchackenberg:fix/api-key-retry-plaintext

Conversation

@BenediktSchackenberg

@BenediktSchackenberg BenediktSchackenberg commented Apr 2, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #1251.

After an invalid API key during NVIDIA Endpoints onboarding, the CLI showed:

Type 'retry', 'back', or 'exit' [retry]:

Users interpreted this as a place to re-enter their key and pasted it in plaintext (visible in terminal history).

Changes

  1. Visible warning — adds ⚠️ Do NOT paste your API key here before the prompt
  2. Clearer prompt textOptions: retry (re-enter key), back (change provider), exit
  3. Accidental paste guard — detects if the user pastes a credential-shaped string (nvapi-, ghp_, or >40 chars), warns them, and redirects to the secure replaceNamedCredential flow

Before / After

Before:

NVIDIA authorization failed. Re-enter the API key or choose a different provider/model.
  Type 'retry', 'back', or 'exit' [retry]: nvapi-abc123...   ← key pasted here in plaintext

After:

NVIDIA authorization failed. Re-enter the API key or choose a different provider/model.
  ⚠️  Do NOT paste your API key here — use the options below:
  Options: retry (re-enter key), back (change provider), exit [retry]:

Signed-off-by: Benedikt Schackenberg 6381261+BenediktSchackenberg@users.noreply.github.com

Summary by CodeRabbit

  • Bug Fixes

    • Clarified the credential-recovery prompt wording for clearer option presentation.
    • Improved detection of accidental API-key pastes (checks common prefixes, long space-free inputs, and token-like patterns) and forces secure credential re-entry when triggered.
  • Tests

    • Added a regression test to ensure the paste-detection heuristic is space-aware, prefix-aware, and stable across branches.

Copilot AI review requested due to automatic review settings April 2, 2026 08:39

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot wasn't able to review any files in this pull request.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@coderabbitai

coderabbitai Bot commented Apr 2, 2026

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Add a credential paste-guard to onboarding recovery: detect likely API-key pastes (prefixes like nvapi-/ghp_, a no-space long-string heuristic, or regex pattern), warn, call replaceNamedCredential(...) to force secure re-entry, and return "credential" to restart credential entry; existing back/exit/retry handling remains.

Changes

Cohort / File(s) Summary
Credential Recovery Guard
bin/lib/onboard.js
Prompt now shows "Options:" and normalizes input; adds paste-guard checks using API_KEY_PREFIXES (including nvapi-, ghp_), a !choice.includes(" ") && choice.length > 40 heuristic, and a regex fallback; hoists NVIDIA-specific validator const for reuse; logs warnings and calls replaceNamedCredential(credentialEnv, \${label} API key`, helpUrl, validator)and returns"credential"` when a paste is detected.
Regression Test
test/credential-exposure.test.js
Adds a Vitest regression test asserting presence/structure of the paste-guard: API_KEY_PREFIXES contains "nvapi-" and "ghp_"; the space-aware long-string check exists; a regex fallback for token-like strings exists; validator for NVIDIA appears only once; looksLikeToken identifier is present.

Sequence Diagram(s)

sequenceDiagram
  participant User as "User"
  participant CLI as "Onboard CLI\n(bin/lib/onboard.js)"
  participant Store as "Credential Store\n(replaceNamedCredential)"
  participant Validator as "NVIDIA Validator\n(conditional)"

  User->>CLI: Enter response at recovery prompt
  CLI->>CLI: normalize choice (trim/toLowerCase)
  CLI-->>CLI: check paste-guard (prefixes / no-space+len / regex)
  alt looks like credential
    CLI->>User: log warning, request secure credential re-entry
    CLI->>Store: replaceNamedCredential(..., validator)
    Store-->>CLI: ack -> returns "credential" flow
  else other option
    CLI->>CLI: handle back / exit / retry as before
  end
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 I sniff the paste where secrets roam,
A careful hop to keep them home.
If keys appear where prompts may glow,
I nudge them back, safe paths to go.
🥕🔒

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: preventing API key plaintext exposure in the retry prompt, which is the core security fix addressed in the PR.
Linked Issues check ✅ Passed The PR fully addresses all coding requirements from #1251: implements an accidental-paste guard with prefix matching, space-aware heuristic, regex fallback, clearer prompt text, and secure credential redirection.
Out of Scope Changes check ✅ Passed All changes are directly in scope: guard logic, prefix detection, validator hoisting, test assertions, and prompt improvements all target the stated objectives of preventing plaintext API key exposure.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
bin/lib/onboard.js (1)

693-715: ⚠️ Potential issue | 🟠 Major

Treat all non-command input as secure credential retry.

At Line 693, the guard is heuristic-based; unrecognized but shorter inputs still fall through to Line 713 ("selection"). In this credential-recovery branch, it’s safer to route any non-navigation input to replaceNamedCredential(...) so mistakes always recover through hidden input.

🔧 Proposed fix
-    // Guard against the user accidentally pasting an API key at this prompt.
-    if (choice.startsWith("nvapi-") || choice.startsWith("ghp_") || choice.length > 40) {
-      console.log("  ⚠️  That looks like an API key — do not paste credentials here.");
-      console.log("  Treating as 'retry'. You will be prompted to enter the key securely.");
-      const validator = credentialEnv === "NVIDIA_API_KEY" ? validateNvidiaApiKeyValue : null;
-      await replaceNamedCredential(credentialEnv, `${label} API key`, helpUrl, validator);
-      return "credential";
-    }
+    const isCommand =
+      choice === "" || choice === "retry" || choice === "back" || choice === "exit" || choice === "quit";
+    if (!isCommand) {
+      console.log("  ⚠️  Unrecognized option. For safety, entering credential flow.");
+      const validator = credentialEnv === "NVIDIA_API_KEY" ? validateNvidiaApiKeyValue : null;
+      await replaceNamedCredential(credentialEnv, `${label} API key`, helpUrl, validator);
+      return "credential";
+    }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bin/lib/onboard.js` around lines 693 - 715, The current handling of `choice`
lets short/unrecognized inputs fall through to the selection branch; instead
treat any non-navigation input as a secure-credential retry by calling
`replaceNamedCredential(...)` and returning "credential". Concretely: keep the
existing special-case for API-key-looking inputs (the
`choice.startsWith("nvapi-") || choice.startsWith("ghp_") || choice.length > 40`
branch) and keep the navigation branches (`choice === "back"`, `choice ===
"exit" || choice === "quit"` calling `exitOnboardFromPrompt()`), but replace the
final fallback so that any other `choice` value (i.e., not back/exit/quit)
invokes `replaceNamedCredential(credentialEnv, \`\${label} API key\`, helpUrl,
credentialEnv === "NVIDIA_API_KEY" ? validateNvidiaApiKeyValue : null)` and then
returns "credential" instead of returning "selection" or printing the retry
prompt.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@bin/lib/onboard.js`:
- Around line 693-715: The current handling of `choice` lets short/unrecognized
inputs fall through to the selection branch; instead treat any non-navigation
input as a secure-credential retry by calling `replaceNamedCredential(...)` and
returning "credential". Concretely: keep the existing special-case for
API-key-looking inputs (the `choice.startsWith("nvapi-") ||
choice.startsWith("ghp_") || choice.length > 40` branch) and keep the navigation
branches (`choice === "back"`, `choice === "exit" || choice === "quit"` calling
`exitOnboardFromPrompt()`), but replace the final fallback so that any other
`choice` value (i.e., not back/exit/quit) invokes
`replaceNamedCredential(credentialEnv, \`\${label} API key\`, helpUrl,
credentialEnv === "NVIDIA_API_KEY" ? validateNvidiaApiKeyValue : null)` and then
returns "credential" instead of returning "selection" or printing the retry
prompt.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 6f0a5a6d-1673-4e5b-96d9-a57765bfe212

📥 Commits

Reviewing files that changed from the base of the PR and between db65da8 and 3b24a36.

📒 Files selected for processing (1)
  • bin/lib/onboard.js

@prekshivyas prekshivyas left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @BenediktSchackenberg — this addresses a real security/UX gap from #1251. The warning text and redirect to replaceNamedCredential are the right approach.

Two items to address:

1. choice.length > 40 false-positive on typed sentences

The heuristic catches pasted tokens, but it will also trigger on normal typed input like:

"I don't understand what to do here can you help me" (52 chars)

That would silently redirect the user into the credential re-entry flow, which is confusing. Suggestion — add a no-spaces check to distinguish a pasted token from a typed sentence:

if (choice.startsWith("nvapi-") || choice.startsWith("ghp_") || (!choice.includes(" ") && choice.length > 40)) {

Tokens don't contain spaces; human sentences do. The nvapi- and ghp_ prefix checks can stay as-is since those are unambiguous.

2. Missing test coverage

The existing codebase has tests for promptValidationRecovery flows. Could you add at least one test that exercises the paste-guard detection path? Something like: input "nvapi-fake-key-value" → verify it returns "credential" and calls replaceNamedCredential.

BenediktSchackenberg added a commit to BenediktSchackenberg/NemoClaw that referenced this pull request Apr 2, 2026
Per prekshivyas review (NVIDIA#1313):

1. Add !choice.includes(' ') to the length-based heuristic to avoid
   false-positives when users type long help sentences (e.g. 52-char
   questions). Tokens don't contain spaces; human sentences do.

2. Add a static test in credential-exposure.test.js verifying:
   - nvapi- and ghp_ prefix checks are present
   - The length check uses the space-aware form
   - A bare choice.length > 40 without the space guard is absent

Signed-off-by: Benedikt Schackenberg <6381261+BenediktSchackenberg@users.noreply.github.com>
@BenediktSchackenberg

Copy link
Copy Markdown
Contributor Author

Both addressed:

  1. Space-aware heuristic — changed to (!choice.includes(" ") && choice.length > 40) so long typed sentences (e.g. 52-char help questions) don't trigger the redirect. Tokens don't contain spaces; human sentences do.

  2. Test coverage — added a static assertion in credential-exposure.test.js that verifies: nvapi-/ghp_ prefix checks are present, the length check uses the space-aware form, and a bare choice.length > 40 without the space guard is absent.

@wscurran wscurran added security Potential vulnerability, unsafe behavior, or access risk priority: high labels Apr 3, 2026
@BenediktSchackenberg

Copy link
Copy Markdown
Contributor Author

@prekshivyas — both items from your review are addressed in the latest commit:

  1. Space-aware heuristic — changed to (!choice.includes(" ") && choice.length > 40). Human sentences contain spaces; API tokens don't. Long typed sentences (e.g. 52-char help questions) no longer trigger the redirect.

  2. Test coverage — added assertion in test/credential-exposure.test.js verifying: nvapi-/ghp_ prefix checks are present, the length check uses the space-aware form, and a bare choice.length > 40 without the space guard is absent.

Ready for re-review!

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
bin/lib/onboard.js (1)

703-717: Hoist shared validator selection to a single definition.

validator is resolved twice with the same expression (Lines 703 and 716). Hoisting it once above the guard reduces duplication and avoids drift.

♻️ Proposed cleanup
+    const validator = credentialEnv === "NVIDIA_API_KEY" ? validateNvidiaApiKeyValue : null;
     if (
       choice.startsWith("nvapi-") ||
       choice.startsWith("ghp_") ||
       (!choice.includes(" ") && choice.length > 40)
     ) {
       console.log("  ⚠️  That looks like an API key — do not paste credentials here.");
       console.log("  Treating as 'retry'. You will be prompted to enter the key securely.");
-      const validator = credentialEnv === "NVIDIA_API_KEY" ? validateNvidiaApiKeyValue : null;
       await replaceNamedCredential(credentialEnv, `${label} API key`, helpUrl, validator);
       return "credential";
     }
@@
     if (choice === "" || choice === "retry") {
-      const validator = credentialEnv === "NVIDIA_API_KEY" ? validateNvidiaApiKeyValue : null;
       await replaceNamedCredential(credentialEnv, `${label} API key`, helpUrl, validator);
       return "credential";
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bin/lib/onboard.js` around lines 703 - 717, The code computes the same
validator twice; move the validator resolution into a single definition before
the choice guards so both the "credential" and the ""/"retry" branches use the
same value. Specifically, compute const validator = credentialEnv ===
"NVIDIA_API_KEY" ? validateNvidiaApiKeyValue : null once (above the if (choice
=== ...) blocks) and then call await replaceNamedCredential(credentialEnv,
`${label} API key`, helpUrl, validator) in both branches, removing the
duplicated assignment.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@bin/lib/onboard.js`:
- Around line 696-700: The current heuristic in the prompt uses only
choice.startsWith("nvapi-") / choice.startsWith("ghp_") and length>40, which
misses shorter provider keys; update the check that examines the variable choice
(in onboard.js) to use a maintainable list of known API key prefixes (e.g.,
include nvapi-, ghp_, gcm-, sk-, gpt-, gemini- etc.) and replace the single
startsWith checks with a started-by-any-prefix test, and additionally add a
regex fallback (e.g., a URL/base64-safe token pattern with a lower length
threshold) so keys without spaces that match common token formats are caught
even if shorter than 40; ensure references to the variable name choice and the
new PREFIX list (e.g., API_KEY_PREFIXES) are used so the logic is easy to
extend.

---

Nitpick comments:
In `@bin/lib/onboard.js`:
- Around line 703-717: The code computes the same validator twice; move the
validator resolution into a single definition before the choice guards so both
the "credential" and the ""/"retry" branches use the same value. Specifically,
compute const validator = credentialEnv === "NVIDIA_API_KEY" ?
validateNvidiaApiKeyValue : null once (above the if (choice === ...) blocks) and
then call await replaceNamedCredential(credentialEnv, `${label} API key`,
helpUrl, validator) in both branches, removing the duplicated assignment.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 677dd069-1692-46b7-8ba6-d7cf0385ac41

📥 Commits

Reviewing files that changed from the base of the PR and between 85c8d25 and 6a685b2.

📒 Files selected for processing (1)
  • bin/lib/onboard.js

Comment thread bin/lib/onboard.js Outdated
@BenediktSchackenberg

Copy link
Copy Markdown
Contributor Author

Addressed both CodeRabbit comments:

  1. Prefix list — replaced bare startsWith checks with an extensible API_KEY_PREFIXES array (nvapi-, ghp_, gcm-, sk-, gpt-, gemini-, nvcf-) plus a regex fallback for base64-safe token patterns (/^[A-Za-z0-9_\-.]{20,}/) to catch shorter keys without known prefixes.

  2. Hoisted validatorconst validator is now defined once above the guard, shared by both the paste-redirect and the retry branches.

Test updated accordingly.

@BenediktSchackenberg BenediktSchackenberg force-pushed the fix/api-key-retry-plaintext branch from 0edf541 to 2252212 Compare April 6, 2026 13:58
BenediktSchackenberg added a commit to BenediktSchackenberg/NemoClaw that referenced this pull request Apr 6, 2026
Per prekshivyas review (NVIDIA#1313):

1. Add !choice.includes(' ') to the length-based heuristic to avoid
   false-positives when users type long help sentences (e.g. 52-char
   questions). Tokens don't contain spaces; human sentences do.

2. Add a static test in credential-exposure.test.js verifying:
   - nvapi- and ghp_ prefix checks are present
   - The length check uses the space-aware form
   - A bare choice.length > 40 without the space guard is absent

Signed-off-by: Benedikt Schackenberg <6381261+BenediktSchackenberg@users.noreply.github.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@test/credential-exposure.test.js`:
- Around line 107-113: Tighten the guards: require the validator declaration to
be present exactly once by changing the validatorCount check from <= 1 to === 1
(reference: validatorCount and the src.match call that searches for 'const
validator = credentialEnv === "NVIDIA_API_KEY"'), make the regex-fallback
assertion more specific by replacing the overly-permissive /\/\^\[A-Za-z0-9/
with a stricter token-regex that anchors and requires a realistic token
character class and minimum length (reference: the expect(src).toMatch(...)
line), and explicitly assert that the looksLikeToken identifier exists in the
generated source (reference: looksLikeToken) so the test fails if the variable
is missing.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 31f69f57-fcfb-4aea-aa4a-cb9bde19ffa5

📥 Commits

Reviewing files that changed from the base of the PR and between 0edf541 and 2252212.

📒 Files selected for processing (2)
  • bin/lib/onboard.js
  • test/credential-exposure.test.js
🚧 Files skipped from review as they are similar to previous changes (1)
  • bin/lib/onboard.js

Comment thread test/credential-exposure.test.js Outdated
@BenediktSchackenberg

Copy link
Copy Markdown
Contributor Author

Tightened both assertions per CodeRabbit:

  • validatorCount changed to === 1 (missing validator now fails the test)
  • Regex-fallback assertion now matches the full pattern shape including minimum length and .test(choice) call

@cv cv added v0.0.11 and removed v0.0.11 labels Apr 9, 2026
Signed-off-by: Benedikt Schackenberg <6381261+BenediktSchackenberg@users.noreply.github.com>
Per prekshivyas review (NVIDIA#1313):

1. Add !choice.includes(' ') to the length-based heuristic to avoid
   false-positives when users type long help sentences (e.g. 52-char
   questions). Tokens don't contain spaces; human sentences do.

2. Add a static test in credential-exposure.test.js verifying:
   - nvapi- and ghp_ prefix checks are present
   - The length check uses the space-aware form
   - A bare choice.length > 40 without the space guard is absent

Signed-off-by: Benedikt Schackenberg <6381261+BenediktSchackenberg@users.noreply.github.com>
…allback

Per CodeRabbit review:
1. Replace bare startsWith checks with an extensible API_KEY_PREFIXES array
   (nvapi-, ghp_, gcm-, sk-, gpt-, gemini-, nvcf-)
2. Add regex fallback for base64-safe token patterns (/^[A-Za-z0-9_\-.]{20,}/)
   to catch shorter keys without known prefixes
3. Hoist validator const above the guard to avoid duplication
4. Update test to verify prefix list, looksLikeToken var, and hoisted validator

Signed-off-by: Benedikt Schackenberg <6381261+BenediktSchackenberg@users.noreply.github.com>
Per CodeRabbit: two assertions were too permissive for a security
regression test:
- validatorCount <= 1 → === 1 (missing validator would no longer pass)
- regex-fallback assertion now matches the full pattern shape including
  minimum length and test() call

Signed-off-by: Benedikt Schackenberg <6381261+BenediktSchackenberg@users.noreply.github.com>
@BenediktSchackenberg BenediktSchackenberg force-pushed the fix/api-key-retry-plaintext branch from 30e2af6 to 6a831e8 Compare April 13, 2026 18:24
@prekshivyas prekshivyas self-assigned this Apr 13, 2026
@cv cv dismissed prekshivyas’s stale review April 14, 2026 00:08

Superseded: the no-spaces guard is in place, the paste-guard path now has dedicated test coverage, and the full PR workflow is green.

@ericksoa ericksoa added v0.0.16 and removed v0.0.15 labels Apr 14, 2026

@ericksoa ericksoa left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed: paste-guard heuristics are sound — prefix list, length+no-space, regex fallback. Low false-positive risk on the happy path. Tests cover detection and secure re-prompt flow.

@ericksoa ericksoa merged commit 0c5392e into NVIDIA:main Apr 14, 2026
11 checks passed
@ericksoa ericksoa added v0.0.15 and removed v0.0.16 labels Apr 14, 2026
ericksoa pushed a commit to cheese-head/NemoClaw that referenced this pull request Apr 14, 2026
…DIA#1313)

## Summary

Fixes NVIDIA#1251.

After an invalid API key during NVIDIA Endpoints onboarding, the CLI
showed:
```
Type 'retry', 'back', or 'exit' [retry]:
```
Users interpreted this as a place to re-enter their key and pasted it in
plaintext (visible in terminal history).

## Changes

1. **Visible warning** — adds `⚠️ Do NOT paste your API key here` before
the prompt
2. **Clearer prompt text** — `Options: retry (re-enter key), back
(change provider), exit`
3. **Accidental paste guard** — detects if the user pastes a
credential-shaped string (`nvapi-`, `ghp_`, or >40 chars), warns them,
and redirects to the secure `replaceNamedCredential` flow

## Before / After

**Before:**
```
NVIDIA authorization failed. Re-enter the API key or choose a different provider/model.
  Type 'retry', 'back', or 'exit' [retry]: nvapi-abc123...   ← key pasted here in plaintext
```

**After:**
```
NVIDIA authorization failed. Re-enter the API key or choose a different provider/model.
  ⚠️  Do NOT paste your API key here — use the options below:
  Options: retry (re-enter key), back (change provider), exit [retry]:
```

Signed-off-by: Benedikt Schackenberg
<6381261+BenediktSchackenberg@users.noreply.github.com>

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Clarified the credential-recovery prompt wording for clearer option
presentation.
* Improved detection of accidental API-key pastes (checks common
prefixes, long space-free inputs, and token-like patterns) and forces
secure credential re-entry when triggered.

* **Tests**
* Added a regression test to ensure the paste-detection heuristic is
space-aware, prefix-aware, and stable across branches.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: Benedikt Schackenberg <6381261+BenediktSchackenberg@users.noreply.github.com>
Co-authored-by: Prekshi Vyas <34834085+prekshivyas@users.noreply.github.com>
Co-authored-by: Carlos Villela <cvillela@nvidia.com>
ColinM-sys pushed a commit to ColinM-sys/NemoClaw that referenced this pull request Apr 14, 2026
…DIA#1313)

## Summary

Fixes NVIDIA#1251.

After an invalid API key during NVIDIA Endpoints onboarding, the CLI
showed:
```
Type 'retry', 'back', or 'exit' [retry]:
```
Users interpreted this as a place to re-enter their key and pasted it in
plaintext (visible in terminal history).

## Changes

1. **Visible warning** — adds `⚠️ Do NOT paste your API key here` before
the prompt
2. **Clearer prompt text** — `Options: retry (re-enter key), back
(change provider), exit`
3. **Accidental paste guard** — detects if the user pastes a
credential-shaped string (`nvapi-`, `ghp_`, or >40 chars), warns them,
and redirects to the secure `replaceNamedCredential` flow

## Before / After

**Before:**
```
NVIDIA authorization failed. Re-enter the API key or choose a different provider/model.
  Type 'retry', 'back', or 'exit' [retry]: nvapi-abc123...   ← key pasted here in plaintext
```

**After:**
```
NVIDIA authorization failed. Re-enter the API key or choose a different provider/model.
  ⚠️  Do NOT paste your API key here — use the options below:
  Options: retry (re-enter key), back (change provider), exit [retry]:
```

Signed-off-by: Benedikt Schackenberg
<6381261+BenediktSchackenberg@users.noreply.github.com>

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Clarified the credential-recovery prompt wording for clearer option
presentation.
* Improved detection of accidental API-key pastes (checks common
prefixes, long space-free inputs, and token-like patterns) and forces
secure credential re-entry when triggered.

* **Tests**
* Added a regression test to ensure the paste-detection heuristic is
space-aware, prefix-aware, and stable across branches.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: Benedikt Schackenberg <6381261+BenediktSchackenberg@users.noreply.github.com>
Co-authored-by: Prekshi Vyas <34834085+prekshivyas@users.noreply.github.com>
Co-authored-by: Carlos Villela <cvillela@nvidia.com>
Signed-off-by: ColinM-sys <cmcdonough@50words.com>
ericksoa added a commit to robobryce/NemoClaw that referenced this pull request Apr 27, 2026
Resolves a merge conflict in test/onboard-selection.test.ts, where main
had retyped the lambda parameter to (line: string) while this PR
clarified the assertion text to "Invalid NVIDIA API key. Must start
with nvapi-". Combined: typed parameter + the new assertion string.

Also updates test/credential-exposure.test.ts:114 ("api-key paste-guard
uses extensible prefix list and regex fallback") to match the rewritten
validator line in src/lib/onboard.ts. The original test (added by PR
NVIDIA#1313) asserted the source contained `const validator = credentialEnv
=== "NVIDIA_API_KEY"`; this PR refactors that to a one-line provider-
aware delegate `(key) => validateNvidiaApiKeyValue(key, credentialEnv)`,
so the regression test's regex needs to match the new shape. The
underlying single-definition invariant from NVIDIA#1313 is preserved.

Pushed by maintainer (Allow edits by maintainers is enabled on this PR).

Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
@wscurran wscurran added area: cli Command line interface, flags, terminal UX, or output bug-fix PR fixes a bug or regression and removed priority: high labels Jun 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: cli Command line interface, flags, terminal UX, or output bug-fix PR fixes a bug or regression security Potential vulnerability, unsafe behavior, or access risk

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[All Platform] After an invalid NVIDIA API key is entered, the retry flow display the API key in plaintext in the terminal

6 participants