Skip to content

Moving a quarantined skill outside managed_dir reclassifies Hub to Local, silently promoting it to Trusted #6707

Description

@bug-ops

Description

Split out from #6702 (impl-critic finding S6, deferred during that PR's review as a pre-existing trust-model behavior unrelated to AutoSkill/trace-extraction specifically — it applies to any quarantined skill, by any origin).

In update_trust_for_reloaded_skills's source_kind-mismatch branch (crates/zeph-core/src/agent/skill_reload.rs, ~lines 133-142): when a skill's classified SourceKind changes between reloads (e.g. HubLocal), the preserve-existing-trust-level branch is skipped even if the file's content (and hash) are unchanged, and trust falls back to *initial_level for the new source kind. Quarantined.is_active() is true and its severity() (2) is greater than Trusted's (0), so the mismatch guard takes *initial_level rather than keeping the higher Quarantined level.

classify_source_kind returns Local for anything outside managed_dir, and [skills.trust] local_level defaults to Trusted (crates/zeph-config/src/security.rs). So: moving (or copying) a Quarantined skill's directory from inside managed_dir to anywhere else — contents unchanged, hash still matches — flips its SourceKind from Hub to Local and promotes it straight to Trusted on the next reload, with no review step.

This is precisely the scenario in #6702's original Expected Behavior text ("Moving a skill directory aside... should reliably keep it out of loading/matching/trust-promotion, regardless of default_level") — except in reverse: moving a quarantined skill out of the managed tree, rather than moving a draft into an operator-named subdirectory within it. #6702's fix (eager trust-row write for AutoSkill drafts) does not address this, since it only prevents trust from being assigned in the first place absent an existing row — it does nothing to prevent an existing Quarantined row from being escalated on a legitimate content-preserving relocation.

Reproduction Steps

  1. Have a skill with an existing skill_trust row at Quarantined (any origin — AutoSkill draft, manually quarantined, etc.) living inside managed_dir.
  2. Move (not copy — content and hash must be identical) its directory to a location outside managed_dir (or, depending on setup, to a location that reclassifies as Local rather than Hub).
  3. Trigger a reload (file watcher fires on removal from the old location / addition at the new one, or restart the agent).
  4. Inspect the skill_trust row for that skill afterward.

Expected Behavior

Trust level should not silently escalate on a pure relocation of unchanged content. At minimum, a source_kind change should never move a skill's effective trust level to something higher than what it already had, absent explicit operator action — the mismatch branch should compare severities and take the lower of *initial_level and the existing preserved level, not blindly the new source kind's default.

Actual Behavior

QuarantinedTrusted promotion on a content-identical relocation from managed_dir (Hub) to anywhere else (Local), since local_level commonly defaults to Trusted.

Environment

Suggested direction (non-binding)

In the source_kind-mismatch branch of update_trust_for_reloaded_skills, when hash matches but source_kind doesn't, take min(severity(*initial_level), severity(existing.trust_level)) rather than unconditionally *initial_level — i.e. a relocation can only ever hold or lower effective trust, never raise it, without an explicit operator action resetting the row.

Related

Metadata

Metadata

Assignees

Labels

P2High value, medium complexitybugSomething isn't workingsecuritySecurity-related issueskillszeph-skills crate

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions