Skip to content

fix(skills): prevent private background review writes - #73373

Open
AIalliAI wants to merge 2 commits into
NousResearch:mainfrom
AIalliAI:fix/skill-privacy-safety
Open

fix(skills): prevent private background review writes#73373
AIalliAI wants to merge 2 commits into
NousResearch:mainfrom
AIalliAI:fix/skill-privacy-safety

Conversation

@AIalliAI

Copy link
Copy Markdown
Contributor

What does this PR do?

Prevents autonomous background review from turning private, session-specific, transient, or unverified material into reusable skills.

The change corrects the root cause at both layers:

  • Prompt policy now treats skills as shareable, durable procedures. Personal identity and preferences stay in memory, and Nothing to save. is valid when no reusable procedure was verified.
  • Runtime enforcement rejects concrete user-home paths and non-placeholder email addresses before autonomous writes are staged, checks the complete result of fuzzy patches, preserves background provenance across approval replay, and forces security scanning for every autonomous mutation.
  • Autonomous scanner failures now fail closed and roll back the write. Foreground skill writes retain the existing opt-in scanner behavior.
  • Backup/snapshot filenames are rejected inside live skill packages; curator backups remain outside the active package.

Related Issue

N/A — proactive privacy and provenance hardening after auditing autonomous skill-review behavior.

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 🔒 Security fix
  • 📝 Documentation update
  • ✅ Tests (adding or improving test coverage)
  • ♻️ Refactor (no behavior change)
  • 🎯 New skill (bundled or hub)

Changes Made

  • Updated agent/background_review.py, agent/prompt_builder.py, and agent/learn_prompt.py to separate reusable procedure from personal memory and transient session state.
  • Added autonomous content hygiene, mandatory fail-closed scanning, approval-origin preservation, and backup-artifact rejection in tools/skill_manager_tool.py.
  • Replaced obsolete active-write prompt contracts and added behavioral regressions for private-path/email rejection, placeholder acceptance, patch-result validation, scanner failure, approval replay, and prompt boundaries.

How to Test

  1. Run scripts/run_tests.sh tests/run_agent/test_review_prompt_class_first.py tests/run_agent/test_background_review.py tests/tools/test_skill_manager_tool.py tests/tools/test_write_approval.py tests/agent/test_prompt_builder.py tests/agent/test_learn_prompt.py.
  2. Confirm the hermetic result is 388 tests passed, 0 failed.
  3. Run Ruff on the ten changed Python files and git diff --check.

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature (no unrelated commits)
  • I've run pytest tests/ -q and all tests pass
  • I've added tests for my changes (required for bug fixes, strongly encouraged for features)
  • I've tested on my platform: macOS 27.0.0 (Apple Silicon)

Documentation & Housekeeping

  • I've updated relevant documentation (README, docs/, docstrings) — N/A; behavior is documented in the prompt policy and code docstrings
  • I've updated cli-config.yaml.example if I added/changed config keys — N/A; no config changes
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — N/A
  • I've considered cross-platform impact (Windows, macOS) per the compatibility guide; content validation covers POSIX and Windows home paths
  • I've updated tool descriptions/schemas if I changed tool behavior — N/A; the existing skill_manage schema is unchanged

Screenshots / Logs

Focused hermetic gate after rebasing onto current origin/main:

=== Summary: 6 files, 388 tests passed, 0 failed (100% complete) ===

Changed-file Ruff and git diff --check both pass. Cache-safety review is clean: only startup prompt constants changed; no conversation-loop mutation, role changes, toolset swaps, or pagination were introduced.

The full repository wrapper was also run. It initially reported 43 failures across 18 files plus one timeout. Five were obsolete prompt-contract tests affected by this patch and were corrected; the remaining 38 failures across 17 untouched files are unrelated platform/concurrency baseline failures (including /tmp versus /private/tmp assertions and Linux systemctl expectations on macOS). The affected hermetic suite above is green.

@alt-glitch alt-glitch added type/security Security vulnerability or hardening P3 Low — cosmetic, nice to have comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint tool/skills Skills system (list, view, manage) labels Jul 28, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

Related: #72319 addresses unresolved outcomes becoming skills, while #55657 and #55665 addressed earlier background-review write-corruption safeguards. This PR adds separate privacy/provenance controls.

@AIalliAI
AIalliAI force-pushed the fix/skill-privacy-safety branch from 8ae2949 to a9496ad Compare July 28, 2026 19:02
@AIalliAI
AIalliAI force-pushed the fix/skill-privacy-safety branch from a9496ad to 0f1133b Compare July 29, 2026 12:05

@teknium1 teknium1 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 for the focused privacy and provenance hardening. The underlying behavior is still present on current main: agent/background_review.py:181-205 promotes personal style/preferences into skill updates, and agent/background_review.py:219-227 permits session-specific reference material.

Problems

  • tools/skill_manager_tool.py:901 rejects backup-style filenames through _validate_file_path(), but the same validator is used by _remove_file() at tools/skill_manager_tool.py:1401. A legacy references/foo.md.bak cannot be removed through skill_manage, so the package cannot be cleaned through the managed interface.
  • tools/skill_manager_tool.py:114 misses /mnt/c/Users/alice/...; its preceding c fails the negative lookbehind. This is a documented Hermes WSL path form in agent/prompt_builder.py:965-973, so it bypasses the proposed autonomous home-path hygiene check.

Suggested changes

  • Reject artifact names on write/overwrite paths only, and add a removal regression.
  • Add WSL-mounted Windows-home matching and a corresponding autonomous-write regression.

The PR is currently conflicting with main and its target test files were pruned after its base, so salvage will require conflict-aware test placement. Automated hermes-sweeper review.


normalized = Path(file_path)

if _BACKUP_ARTIFACT_RE.search(normalized.name):

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.

_validate_file_path() is also used by _remove_file() (line 1401), so this prevents removing an existing references/foo.md.bak. Apply this rejection only to creation/overwrite paths and add a regression proving legacy artifacts remain removable.

r"(?P<domain>[A-Za-z0-9-]+(?:\.[A-Za-z0-9-]+)+)"
)
_POSIX_HOME_RE = re.compile(
r"(?<![A-Za-z0-9])/(?:Users|home)/(?P<account>[^/\s`'\"<>]+)"

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.

/mnt/c/Users/alice/... does not match because the c before /Users fails this lookbehind. Hermes documents that exact WSL path form in agent/prompt_builder.py:965-973; include it in the privacy matcher and test it.

@teknium1 teknium1 added sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-massive Sweeper blast radius: massive — everyone, every turn (invariant surface) labels Jul 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint P3 Low — cosmetic, nice to have sweeper:blast-massive Sweeper blast radius: massive — everyone, every turn (invariant surface) sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data tool/skills Skills system (list, view, manage) type/security Security vulnerability or hardening

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants