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

    type/bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions