Skip to content

fix(security): scrub migration and backup credentials consistently - #7765

Closed
Ayush7614 wants to merge 3 commits into
NVIDIA:mainfrom
Ayush7614:fix/credential-sanitize-migration-backup
Closed

fix(security): scrub migration and backup credentials consistently#7765
Ayush7614 wants to merge 3 commits into
NVIDIA:mainfrom
Ayush7614:fix/credential-sanitize-migration-backup

Conversation

@Ayush7614

@Ayush7614 Ayush7614 commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Summary

Host-to-sandbox migration and rebuild backups used a weaker credential scrubber than the shared filter, so Slack botToken / appToken, Authorization headers, env secrets such as GITHUB_TOKEN and DB_PASS, and Hermes config.yaml secrets could survive into snapshots. This change routes both paths through the hardened scrubbing rules so those values are stripped (or excluded) before backup or migration copy.

Changes

  • Extended src/lib/security/credential-filter.ts with sanitizeEnvFile / sanitizeEnvFileContent, YAML config sanitization, and snapshot scanning for .yaml / .yml (still excluding dependency lockfiles).
  • Updated rebuild backup walk in src/lib/state/sandbox.ts to sanitize JSON, Hermes YAML, and .env via the shared helpers instead of the ad-hoc KEY|TOKEN|SECRET|PASSWORD|CREDENTIAL substring regex.
  • Added nemoclaw/src/security/credential-filter.ts and wired host→sandbox migration in nemoclaw/src/commands/migration-state.ts to it so migration strips the same field classes (channel tokens, headers, env secrets, CLI flag args, value-shaped secrets) and excludes auth.json / chatgpt-auth.json as well as auth-profiles.json.
  • Expanded unit coverage in src/lib/security/credential-filter.test.ts and nemoclaw/src/security/credential-filter.test.ts.

Type of Change

  • Code change (feature, bug fix, or refactor)
  • Code change with doc updates
  • Doc only (prose changes, no code sample modifications)
  • Doc only (includes code sample changes)

Quality Gates

  • Tests added or updated for changed behavior
  • Existing tests cover changed behavior — justification:
  • Tests not applicable — justification:
  • Docs updated for user-facing behavior changes
  • Docs not applicable — justification: Internal sanitization behavior only; no user-facing install, configure, or operate docs change.
  • Sensitive paths changed (security, policy, credentials, preflight, onboarding, inference, runner, sandbox, or messaging)
  • Sensitive-path review completed or maintainer-approved waiver recorded — reviewer/approval link/justification: Awaiting maintainer security review on this PR.
  • Non-success, skipped, or missing CI check accepted by maintainer — check name, approval link, and follow-up issue:

Documentation Writer Review

  • Documentation writer subagent reviewed the completed changes
  • Result: no-docs-needed
  • Evidence: No docs/ pages changed. Behavior is internal credential scrubbing for migration snapshots and rebuild backups; users do not configure or observe a new surface.
  • Agent: Cursor

DGX Station Hardware Evidence

  • Tested on DGX Station
  • Tested commit:
  • Station profile/scenario:
  • Result:
  • Supporting evidence:

Verification

  • PR description includes a Signed-off-by: line and every commit appears as Verified in GitHub
  • Normal pre-commit, commit-msg, and pre-push hooks passed, or npm run check:diff passed when hooks were skipped or unavailable
  • Targeted behavior tests pass for the current change set, or tests are marked not applicable above — command/result or justification: npx vitest run --project cli src/lib/security/credential-filter.test.ts src/lib/security/credential-filter-secret-patterns.test.ts → 36 passed; npx vitest run --project plugin nemoclaw/src/security/credential-filter.test.ts → 4 passed; CLI and plugin typecheck passed.
  • Applicable broad gate passed — npm test for broad runtime/test-harness changes; npm run check for repo-wide validation/coverage changes — command/result:
  • Quality Gates section completed with required justifications or waivers
  • No secrets, API keys, or credentials committed
  • npm run docs builds without warnings (doc changes only)
  • Doc pages follow the style guide (doc changes only)
  • New doc pages include SPDX header and frontmatter (new pages only)

Signed-off-by: Ayush7614 ayushknj3@gmail.com

Summary by CodeRabbit

  • Security Enhancements
    • Improved credential detection and scrubbing across migrations, snapshots, and local backups, including nested fields and command-line tokens.
    • Expanded protection for sensitive auth-state files and Hermès YAML configs (.yaml/.yml), including removal of the gateway section.
    • Added consistent sanitization for .env-style content and config files with safer placeholder handling and fail-closed behavior.
  • Bug Fixes
    • Tightened sensitive-file filtering to better prevent accidental bundling/copying of secrets.
  • Tests
    • Added/expanded coverage for placeholder behavior, null/undefined preservation, sensitive filename detection, and YAML/.env sanitization.

@copy-pr-bot

copy-pr-bot Bot commented Jul 28, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

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

Credential sanitization is centralized into shared helpers, extended to YAML and .env files, and integrated into migration snapshot copying and sandbox backup sanitization. Tests cover detection, placeholders, recursive scrubbing, file sanitization, and YAML scanning.

Changes

Credential Sanitization

Layer / File(s) Summary
Shared credential detection and recursive scrubbing
nemoclaw/src/security/credential-filter.ts, nemoclaw/src/security/credential-filter.test.ts
Adds credential detection, placeholder preservation, recursive and CLI argument scrubbing, sensitive filename checks, and tests.
YAML and environment-file sanitization
src/lib/security/credential-filter.ts, src/lib/security/credential-filter.test.ts
Adds YAML and .env sanitization, atomic rewrites, fail-closed YAML handling, and YAML snapshot scanning.
Migration snapshot integration
nemoclaw/src/commands/migration-state.ts
Uses shared sanitization and sensitive-file helpers during configuration sanitization and snapshot copying.
Sandbox backup sanitization wiring
src/lib/state/sandbox.ts
Routes JSON/YAML files through sanitizeConfigFile and .env files through sanitizeEnvFile during backup sanitization.

Estimated code review effort: 4 (Complex) | ~45 minutes

Suggested labels: security, bug-fix

Suggested reviewers: cv, ericksoa

Sequence Diagram(s)

sequenceDiagram
  participant BackupWalker
  participant CredentialFilter
  participant Filesystem
  BackupWalker->>Filesystem: inspect backup files
  BackupWalker->>CredentialFilter: sanitize JSON/YAML configuration
  BackupWalker->>CredentialFilter: sanitize .env files
  CredentialFilter->>Filesystem: atomically write sanitized files
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly captures the main change: consistent credential scrubbing across migration and backup flows.
Docstring Coverage ✅ Passed Docstring coverage is 87.50% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
🔧 Fix failing CI
  • Fix failing CI in branch fix/credential-sanitize-migration-backup

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

@github-actions

github-actions Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

PR Review Advisor — Blocking findings reported

Advisor assessment: Blockers require maintainer review
Next action: Review the blockers below.
Findings: 1 blocker · 0 warnings · 0 suggestions

Model lanes

  • GPT-5.6 Terra (primary): Completed · high confidence · 1 blocker · 0 warnings · 0 suggestions
  • Nemotron 3 Ultra (second opinion): Failed after a partial review · low confidence · 0 blockers · 2 warnings · 0 suggestions

Nemotron output stays in workflow artifacts and does not change the assessment above.

E2E guidance

Advisory only. E2E / PR Gate selects and runs jobs independently.

Recommended E2E: cloud-inference, security-posture, onboard-repair, onboard-resume

3 optional E2E recommendations
  • state-backup-restore
  • rebuild-hermes
  • sandbox-rebuild

Blockers

PRA-1 Blocker — Do not retain files when backup sanitization fails

  • Location: src/lib/state/sandbox.ts:648
  • Category: correctness
  • Problem: The backup sanitization pass ignores failure to delete unsanitized YAML files. It also ignores errors from .env sanitization. A raw credential-bearing file can therefore remain in the backup and later be restored.
  • Impact: Raw sandbox credentials can persist in a rebuild backup and cross the sandbox boundary during a later restore.
  • Fix: Make sanitization failure fail closed for every credential-bearing config and .env file. Remove the file reliably or abort and remove the backup when deletion or sanitization fails; do not suppress that failure.
  • Verification: Mock a malformed YAML file with unlinkSync failure, and a .env sanitizer failure, then inspect the resulting backup directory for the original files.
  • Test coverage: Add a sanitizeBackupDirectory-level regression test that proves a failed YAML cleanup and a failed .env sanitization cannot leave the raw artifact in the retained backup.
  • Evidence: src/lib/state/sandbox.ts:648-666 attempts deletion only for failed YAML sanitization and suppresses deletion and .env sanitization errors. src/lib/state/sandbox.ts:1315 calls sanitizeBackupDirectory after state capture, making this the last local boundary before the backup is retained. src/lib/security/credential-filter.test.ts:255-260 proves malformed YAML returns false but does not exercise backup-directory artifact removal failures.

Workflow run details

This automated review informs maintainers. Warnings and suggestions do not require a response. A maintainer decides whether to merge.

@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 (2)
nemoclaw/src/security/credential-filter.ts (1)

4-6: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate credential-detection logic maintained manually "in parity."

This file's field lists/regexes (CREDENTIAL_FIELDS, CREDENTIAL_FIELD_PATTERN, isCredentialField, stripCredentials, etc.) are near-duplicates of src/lib/security/credential-filter.ts, kept in sync only by convention/comment. Since nemoclaw ships as its own package inside the sandbox image (separate from src/lib), a shared import isn't straightforward, but relying on a manual "kept in parity" comment risks exactly the kind of drift this PR is fixing. Consider a lightweight guard — e.g. a test or script that diffs the exported field lists/patterns between the two files — so future edits to one side fail CI if the other isn't updated.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@nemoclaw/src/security/credential-filter.ts` around lines 4 - 6, Introduce a
lightweight parity guard for the credential-filter implementations, comparing
the exported field lists and credential-detection patterns used by
CREDENTIAL_FIELDS, CREDENTIAL_FIELD_PATTERN, isCredentialField, and
stripCredentials in both files. Make the guard fail CI when either side changes
without the corresponding update, while preserving the separate package
structure and runtime behavior.
src/lib/security/credential-filter.ts (1)

393-437: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

toConfigValue fails closed silently — consider a louder failure mode.

If any nested value can't be represented in ConfigValue (e.g. via a future merge: true/custom-tags change, or an unanticipated YAML construct), toConfigValue bails out with undefined for the entire subtree, and sanitizeYamlConfigFile then just returns without writing anything — leaving the original, unsanitized file on disk with no warning. With the current default parseYaml options this is unlikely to trigger in practice (default core schema only produces JSON-compatible types), but per the security-boundary path instructions this file should "preserve... fail-closed handling" rather than silently pass through. Consider logging/erroring instead of a quiet no-op so a future schema change or unexpected input doesn't silently reintroduce the leak this PR is fixing. Separately, stringifyYaml re-serializing the whole document will drop any existing comments in the source YAML — worth a heads-up for anyone editing Hermes configs by hand.

As per path instructions for src/lib/{security,credentials,shields}/**: "Preserve deny-by-default behavior, least privilege, redaction, and fail-closed handling."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/security/credential-filter.ts` around lines 393 - 437, Make the
conversion failure in toConfigValue fail closed visibly rather than returning
through sanitizeYamlConfigFile silently. Update sanitizeYamlConfigFile to detect
an unrepresentable parsed value, report the failure through the established
error/logging mechanism, and skip writing the original file; preserve the
existing no-write behavior on failure. Ensure sanitization never leaves an
unsanitized file without an observable failure.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/lib/security/credential-filter.ts`:
- Around line 367-382: Update sanitizeEnvFileContent to recognize and remove a
leading export prefix before evaluating the environment variable key, while
preserving the original formatting when replacing the value. Ensure credential
fields such as export DB_PASS are sanitized, and add negative-path coverage
proving export-prefixed secrets cannot bypass filtering or appear in sanitized
output.

---

Nitpick comments:
In `@nemoclaw/src/security/credential-filter.ts`:
- Around line 4-6: Introduce a lightweight parity guard for the
credential-filter implementations, comparing the exported field lists and
credential-detection patterns used by CREDENTIAL_FIELDS,
CREDENTIAL_FIELD_PATTERN, isCredentialField, and stripCredentials in both files.
Make the guard fail CI when either side changes without the corresponding
update, while preserving the separate package structure and runtime behavior.

In `@src/lib/security/credential-filter.ts`:
- Around line 393-437: Make the conversion failure in toConfigValue fail closed
visibly rather than returning through sanitizeYamlConfigFile silently. Update
sanitizeYamlConfigFile to detect an unrepresentable parsed value, report the
failure through the established error/logging mechanism, and skip writing the
original file; preserve the existing no-write behavior on failure. Ensure
sanitization never leaves an unsanitized file without an observable failure.
🪄 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: Enterprise

Run ID: c1aff186-95c1-413e-bccb-c2d3fda1928b

📥 Commits

Reviewing files that changed from the base of the PR and between c4c020c and ddd3fda.

📒 Files selected for processing (6)
  • nemoclaw/src/commands/migration-state.ts
  • nemoclaw/src/security/credential-filter.test.ts
  • nemoclaw/src/security/credential-filter.ts
  • src/lib/security/credential-filter.test.ts
  • src/lib/security/credential-filter.ts
  • src/lib/state/sandbox.ts

Comment thread src/lib/security/credential-filter.ts
@Ayush7614

Copy link
Copy Markdown
Contributor Author

Addressed the CodeRabbit finding on sanitizeEnvFileContent: credential keys with a leading export prefix are now matched and scrubbed, with a negative-path unit test.

Skipped the maintainability nit about adding a cross-package parity guard/script for the duplicated plugin filter — that would be a new CI abstraction without a current breakage, and the plugin package cannot import src/lib directly.

Align host-to-sandbox migration and rebuild backups with the shared
credential filter so bot tokens, env secrets, Authorization headers,
Hermes YAML, and .env PASS fields cannot survive snapshot sanitization.

Signed-off-by: Ayush7614 <ayushknj3@gmail.com>
Shell-sourced env files often use `export KEY=value`, which bypassed
key detection. Strip the prefix before credential-field matching.

Signed-off-by: Ayush7614 <ayushknj3@gmail.com>
@Ayush7614
Ayush7614 force-pushed the fix/credential-sanitize-migration-backup branch from 66cf9d3 to 5759812 Compare July 28, 2026 21:58

@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: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@nemoclaw/src/security/credential-filter.ts`:
- Around line 156-173: Update the credential-field handling in stripCredentials
so null and undefined values remain unchanged instead of being replaced with
CREDENTIAL_PLACEHOLDER. Preserve existing placeholder validation for non-null
credential values and keep the array behavior through scrubArrayElement
unchanged.

In `@src/lib/security/credential-filter.ts`:
- Around line 424-439: Make YAML sanitization fail closed: update
sanitizeYamlConfigFile and the conversion flow around lines 395-417 to return an
explicit failure for parse or unrepresentable-value errors, and ensure no
original artifact remains. Propagate this outcome through the backup caller
around lines 447-465 so failed sanitization causes the copied artifact to be
omitted or deleted. Add negative-path tests for malformed and unsupported YAML
that verify credentials are not retained. Affected sites:
src/lib/security/credential-filter.ts lines 424-439 require failure reporting;
lines 395-417 require unrepresentable-value propagation; lines 447-465 require
exposing and honoring the outcome.
🪄 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: Enterprise

Run ID: 6ffeb9be-65f1-4470-b402-91762092bd48

📥 Commits

Reviewing files that changed from the base of the PR and between 66cf9d3 and 5759812.

📒 Files selected for processing (6)
  • nemoclaw/src/commands/migration-state.ts
  • nemoclaw/src/security/credential-filter.test.ts
  • nemoclaw/src/security/credential-filter.ts
  • src/lib/security/credential-filter.test.ts
  • src/lib/security/credential-filter.ts
  • src/lib/state/sandbox.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/lib/security/credential-filter.test.ts
  • nemoclaw/src/security/credential-filter.test.ts
  • nemoclaw/src/commands/migration-state.ts
  • src/lib/state/sandbox.ts

Comment thread nemoclaw/src/security/credential-filter.ts
Comment thread src/lib/security/credential-filter.ts Outdated
@Ayush7614
Ayush7614 force-pushed the fix/credential-sanitize-migration-backup branch from 5759812 to 48037ba Compare July 28, 2026 22:05
Preserve unset credential fields, omit unsanitizable Hermes YAML from
backups, normalize backup file extensions, and align migration secret
shape detection with the canonical token patterns.

Signed-off-by: Ayush7614 <ayushknj3@gmail.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 current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/lib/security/credential-filter.ts`:
- Around line 427-442: Update sanitizeYamlConfigFile to catch errors from
stringifyYaml and writeFileAtomically during the sanitized YAML rewrite,
returning false when either operation fails so callers take the existing cleanup
path. Preserve the true result only for successful rewrites, and add a
negative-path test covering a failed rewrite.
🪄 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: Enterprise

Run ID: c0192e78-867e-456b-b701-8bbe080c19ca

📥 Commits

Reviewing files that changed from the base of the PR and between 48037ba and 2f9ccb1.

📒 Files selected for processing (5)
  • nemoclaw/src/security/credential-filter.test.ts
  • nemoclaw/src/security/credential-filter.ts
  • src/lib/security/credential-filter.test.ts
  • src/lib/security/credential-filter.ts
  • src/lib/state/sandbox.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/lib/state/sandbox.ts
  • src/lib/security/credential-filter.test.ts
  • nemoclaw/src/security/credential-filter.ts

Comment on lines +427 to +442
export function sanitizeYamlConfigFile(configPath: string): boolean {
const rawConfig = readRegularFileNoFollow(configPath);
if (rawConfig === null) return;
let parsed: ConfigValue;
if (rawConfig === null) return false;
let parsed: unknown;
try {
parsed = parseJson<ConfigValue>(rawConfig);
parsed = parseYaml(rawConfig);
} catch {
return; // Not valid JSON — skip (may be YAML for Hermes)
return false;
}
if (!isConfigObject(parsed)) return;
const configValue = toConfigValue(parsed);
if (!isConfigObject(configValue)) return false;

const { gateway: _gateway, ...config } = parsed;
const { gateway: _gateway, ...config } = configValue;
const sanitized = stripCredentials(config);
writeFileAtomically(configPath, JSON.stringify(sanitized, null, 2));
writeFileAtomically(configPath, stringifyYaml(sanitized));
return true;

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.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify whether the atomic writer can throw and whether callers delete failed YAML artifacts.
rg -n -A30 -B5 'writeFileAtomically' src/lib/security/credential-filter.ts
rg -n -A25 -B5 'sanitizeConfigFile\(fullPath\)' src/lib/state/sandbox.ts

Repository: NVIDIA/NemoClaw

Length of output: 6148


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '420,445p' src/lib/security/credential-filter.ts
printf '\n---\n'
sed -n '635,665p' src/lib/security/credential-filter.ts
printf '\n---\n'
rg -n "sanitizeYamlConfigFile|sanitizeConfigFile\\(" src/lib/security src/lib/state -g '*test.ts' -g '*spec.ts'

Repository: NVIDIA/NemoClaw

Length of output: 1726


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '220,280p' src/lib/security/credential-filter.test.ts
printf '\n---\n'
sed -n '635,660p' src/lib/security/credential-filter.ts
printf '\n---\n'
sed -n '1,220p' src/lib/security/credential-filter.test.ts

Repository: NVIDIA/NemoClaw

Length of output: 11027


Fail closed on YAML rewrite errors.

sanitizeYamlConfigFile() can still throw from stringifyYaml() or writeFileAtomically(), which skips the false path the backup walker relies on to delete raw YAML artifacts. Catch those errors, return false, and add a negative-path test for a failed rewrite.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/security/credential-filter.ts` around lines 427 - 442, Update
sanitizeYamlConfigFile to catch errors from stringifyYaml and
writeFileAtomically during the sanitized YAML rewrite, returning false when
either operation fails so callers take the existing cleanup path. Preserve the
true result only for successful rewrites, and add a negative-path test covering
a failed rewrite.

Source: Path instructions

@wscurran wscurran added area: sandbox OpenShell sandbox lifecycle, runtime, config, or recovery area: security Security controls, permissions, secrets, or hardening bug-fix PR fixes a bug or regression labels Jul 28, 2026
@wscurran

Copy link
Copy Markdown
Contributor

✨ Thanks for the PR. This fixes credential leakage in migration and backup snapshots by routing both paths through the hardened scrubber. Maintainers will review the sanitization coverage, snapshot scanning, and mutation boundary.

@apurvvkumaria apurvvkumaria self-assigned this Jul 29, 2026
senthilr-nv added a commit that referenced this pull request Aug 2, 2026
<!-- markdownlint-disable MD041 -->
## Summary

This is a clean, compliant replacement for #7765 that preserves
@Ayush7614 as the author of the original three commits. Host-to-sandbox
migration and rebuild backups now scrub the same credential shapes, and
backup creation fails closed instead of retaining a raw configuration
when sanitization or cleanup fails.

## Changes

- Share credential-field, token-shape, auth-header, CLI-argument, and
safe-placeholder filtering across migration and rebuild snapshots.
- Recursively sanitize every copied migration JSON, YAML, and `.env`
artifact, including external roots; omit authentication-state files and
malformed artifacts.
- Reject required malformed OpenClaw configuration copies and clean up
incomplete staging directories.
- Delete and reject incomplete rebuild backups if an unsafe artifact
cannot be removed.
- Bind migration and rebuild snapshot traversal and mutations to opened
directory descriptors, fail closed on parent or root identity changes,
and require POSIX `python3` support.
- Scrub common OAuth credential fields, including access, refresh, and
identity tokens.
- Add cross-implementation parity, failure-injection,
malformed-artifact, value-shape, and real backup permission/content
coverage.
- Document that migration and rebuild snapshots are filtered restore
points rather than byte-for-byte copies.

## Type of Change

- [ ] Code change (feature, bug fix, or refactor)
- [x] Code change with doc updates
- [ ] Doc only (prose changes, no code sample modifications)
- [ ] Doc only (includes code sample changes)

## Quality Gates

- [x] Tests added or updated for changed behavior
- [ ] Existing tests cover changed behavior — justification:
- [ ] Tests not applicable — justification:
- [x] Docs updated for user-facing behavior changes
- [ ] Docs not applicable — justification:
- [x] Sensitive paths changed (security, policy, credentials, preflight,
onboarding, inference, runner, sandbox, or messaging)
- [x] Sensitive-path review completed or maintainer-approved waiver
recorded — reviewer/approval link/justification: Codex Desktop completed
the nine-category security review at
`5b8dd525f6297ca6fe1f3b669801c464824e5704`; PASS for
secrets/credentials, input validation/sanitization, authorization
boundaries, dependencies, error handling/logging, data protection,
secure configuration/defaults, security regression testing, and holistic
abuse/availability review. Exact diff fingerprint:
`cbe679f02c0b986b6e02aa4a9aeb7778acb4539f6aca760c5ff6edae8745064a`.
- [ ] Non-success, skipped, or missing CI check accepted by maintainer —
check name, approval link, and follow-up issue:

## Documentation Writer Review

- [x] Documentation writer subagent reviewed the completed changes
- Result: `docs-updated`
- Evidence: Independent Codex Desktop documentation writer review passed
at exact head `5a27ad655cc1329e15ff37e28440762e24cb4dd6`; all three
changed pages and generated OpenClaw, Hermes, and Deep Agents variants
were reviewed; `npm run docs` completed with 0 errors and 2 existing
Fern warnings.
- Agent: Codex Desktop
<!-- docs-review-head-sha: 5a27ad6 -->
<!-- docs-review-agents-blob-sha:
3dd7c24 -->

## DGX Station Hardware Evidence

- [ ] Tested on DGX Station
- Tested commit:
- Station profile/scenario:
- Result:
- Supporting evidence:

## Verification

- [x] PR description includes a `Signed-off-by:` line and every commit
appears as `Verified` in GitHub
- [x] Normal `pre-commit`, `commit-msg`, and `pre-push` hooks passed, or
`npm run validate:pr` passed after refreshing `origin/main` when hooks
were skipped or unavailable
- [x] Targeted behavior tests pass for the current change set, or tests
are marked not applicable above — At exact head `5b8dd525f`, the `27/27`
interpreter-boundary and sanitizer tests, pre-commit guardrails, and
plugin/CLI pre-push typechecks passed. The documentation build passed at
immediately preceding head `eb10756df`; the follow-up changes tests
only. At signed feature commit `d59a0e3b4` before the docs-only main
sync, the full `767/767` plugin suite and coverage ratchet (95.31%
statements / 95.96% lines) passed; the feature diff is unchanged by the
sync.
- [x] Applicable broad gate passed — `npm run validate:pr`; PASS on
current main.
- [x] Quality Gates section completed with required justifications or
waivers
- [x] No secrets, API keys, or credentials committed
- [x] `npm run docs` builds without errors (2 pre-existing warnings)
- [x] Doc pages follow the [style
guide](https://github.com/NVIDIA/NemoClaw/blob/main/docs/CONTRIBUTING.md)
(doc changes only)
- [ ] New doc pages include SPDX header and frontmatter (new pages only)

---
Signed-off-by: Apurv Kumaria <akumaria@nvidia.com>

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

* **Security Enhancements**
* Migration and snapshot bundles now sanitize credentials across JSON,
YAML, and `.env` files while preserving approved placeholders and null
values.
* Sensitive or unsafe artifacts are omitted or removed, with stricter
fail-closed behavior and clearer error reporting.
  * Incomplete backups are cleaned up when sanitization fails.

* **Documentation**
  * Expanded snapshot contents, retention, and sanitization guidance.
* Documented the `python3` POSIX requirement and WSL support for Windows
environments.

* **Tests**
* Added broader credential detection, redaction, parity,
filesystem-safety, and failure-path coverage.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: Ayush7614 <ayushknj3@gmail.com>
Signed-off-by: Apurv Kumaria <akumaria@nvidia.com>
Co-authored-by: Ayush7614 <ayushknj3@gmail.com>
Co-authored-by: Senthil Ravichandran <senthilr@nvidia.com>
Co-authored-by: Carlos Villela <cvillela@nvidia.com>
@apurvvkumaria apurvvkumaria removed their assignment Aug 3, 2026
@apurvvkumaria apurvvkumaria added the v0.0.102 Release target label Aug 4, 2026
@apurvvkumaria apurvvkumaria self-assigned this Aug 4, 2026
@cv

cv commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator

Closing as superseded by merged #7847. The replacement preserves @Ayush7614 as author of the original three signed commits and adds the fail-closed cleanup, traversal hardening, tests, documentation, and security review needed to resolve this PR's outstanding blocker. Thank you, @Ayush7614, for the original fix.

@cv cv closed this Aug 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: sandbox OpenShell sandbox lifecycle, runtime, config, or recovery area: security Security controls, permissions, secrets, or hardening bug-fix PR fixes a bug or regression v0.0.102 Release target

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants