Skip to content

Skills Guard: Official/builtin skills blocked by scan + --force flag doesn't override DANGEROUS verdict #1006

@teknium1

Description

@teknium1

Problem

Two issues with the Skills Guard install flow that prevent installing official optional skills:

1. Official/builtin skills are blocked despite policy allowing them

The INSTALL_POLICY table in tools/skills_guard.py correctly declares that builtin trust level should allow all verdicts including dangerous:

INSTALL_POLICY = {
    #                  safe      caution    dangerous
    "builtin":       ("allow",  "allow",   "allow"),
    ...
}

And _resolve_trust_level() correctly maps official/ sources to "builtin" trust level.

However, should_allow_install() has a hard-coded early return that blocks ALL dangerous verdicts before ever checking the trust-based policy table:

def should_allow_install(result: ScanResult, force: bool = False) -> Tuple[bool, str]:
    if result.verdict == "dangerous":
        return False, f"Scan verdict is DANGEROUS ({len(result.findings)} findings). Blocked."
    # ^ This fires BEFORE the policy table is consulted
    
    policy = INSTALL_POLICY.get(result.trust_level, ...)  # Never reached for dangerous

This means the builtin: ("allow", "allow", "allow") row is dead code — it can never take effect for dangerous verdicts.

Reproduction: Try installing official/email/agentmail — it triggers persistence (mentions ~/.hermes/config.yaml) and supply_chain (mentions pip install mcp) patterns, gets classified as DANGEROUS, and is blocked despite being an official skill with builtin trust.

2. --force flag does not override DANGEROUS blocks

The docstring explicitly says "never overrides dangerous" and the code enforces this — force is only checked after the hard dangerous block (line 653), so it can only override caution-level blocks. This means there is literally no way for a user to install a skill flagged as DANGEROUS, even with --force.

Additionally, the /skills install slash command does not parse --yes — only --force is recognized (line 936 of hermes_cli/skills_hub.py). So /skills install ... --yes --force only applies --force, and --yes is silently ignored.

Proposed Fix

Fix 1: Let the policy table handle builtin/official trust decisions

Reorder should_allow_install() so the trust-based policy table is checked before the hard dangerous block. If the policy says "allow", allow it regardless of verdict. This makes the builtin row actually functional.

def should_allow_install(result: ScanResult, force: bool = False) -> Tuple[bool, str]:
    policy = INSTALL_POLICY.get(result.trust_level, INSTALL_POLICY["community"])
    vi = VERDICT_INDEX.get(result.verdict, 2)
    decision = policy[vi]

    if decision == "allow":
        return True, f"Allowed ({result.trust_level} source, {result.verdict} verdict)"

    if force:
        return True, f"Force-installed despite {result.verdict} verdict ({len(result.findings)} findings)"

    return False, (
        f"Blocked ({result.trust_level} source + {result.verdict} verdict, "
        f"{len(result.findings)} findings). Use --force to override."
    )

This way:

  • builtin (official) skills: always allowed (policy says allow for all verdicts)
  • trusted skills: allowed for safe/caution, blocked for dangerous (overridable with --force)
  • community skills: allowed for safe only, blocked for caution/dangerous (overridable with --force)

Fix 2: --force overrides everything

Remove the hard block on dangerous that prevents --force from working. The revised function above handles this naturally — if the policy says "block", --force overrides it regardless of verdict severity.

Affected Files

  • tools/skills_guard.pyshould_allow_install() (lines 642-669)
  • hermes_cli/skills_hub.py — optional: parse --yes as alias for --force in slash command (line 936)

Severity

High — Users literally cannot install official optional skills that reference config files or mention pip installs, which is most of them.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions