Skip to content

security: verify runtime OpenShell version against credential boundary manifest #6256

Open

Description

@apurvvkumaria

Source

Identified in PR #5876 — feat(mcp): add OpenShell-managed MCP servers, specifically the PR Review Advisor findings.

Problem

The credential boundary manifest openshell-child-visible-credentials.v0.0.72.json is baked for OpenShell 0.0.72 and supplies the deny-lists used to protect child-visible credentials. The TypeScript and Python consumers validate the manifest structure, but neither verifies that the running openshell binary matches manifest.openshellVersion. The Hermes image and startup path also lack an equivalent runtime gate.

A sandbox can therefore use credential-boundary rules for OpenShell 0.0.72 while actually running a newer or older OpenShell after an image, installer, or manual runtime change.

Findings consolidated

PRA-4 — TypeScript validation boundary

Affected paths:

  • src/lib/actions/sandbox/mcp-bridge-validation.ts
  • src/lib/security/mcp-url-target.ts

The manifest is imported and its runtimeControlKeys, runtimeControlPrefixes, rawChildValueKeys, and rewrittenChildValueKeys are used without executing openshell --version.

PRA-5 — Python Hermes transaction boundary

Affected path:

  • agents/hermes/mcp-config-transaction.py

_load_credential_boundary_manifest() checks the baked manifest version but never compares it with the installed OpenShell binary.

PRA-6 — Hermes runtime/startup boundary

Affected paths:

  • agents/hermes/Dockerfile
  • agents/hermes/start.sh
  • agents/hermes/mcp-config-transaction.py

The Dockerfile checks MCP Python imports at build time, but Hermes startup does not verify the runtime OpenShell version before using the credential deny-list.

Security impact

When the manifest and runtime diverge:

  • newly reserved OpenShell credential names may be accepted and exposed across the child credential boundary;
  • names that are legitimate for the running version may be rejected;
  • the credential isolation contract silently depends on stale metadata.

Required behavior

  • Execute and parse openshell --version in the TypeScript credential-validation path.
  • Execute and parse subprocess.run(["openshell", "--version"], capture_output=True, text=True) in the Python/Hermes path.
  • Compare the parsed version exactly with manifest.openshellVersion.
  • Fail closed when the binary is missing, exits unsuccessfully, produces unparseable output, or reports a different version.
  • Ensure the Hermes check runs for every relevant startup. If the Python transaction is guaranteed to execute before credential configuration on every startup, it may satisfy the startup boundary; otherwise add an entrypoint check.
  • A short-lived cache may be used in frequently invoked TypeScript validation, but it must not allow a stale result to survive a runtime change indefinitely.
  • Error output should identify expected versus actual version without exposing credential values.

Regression coverage

  • Add TypeScript tests in src/lib/actions/sandbox/mcp-bridge-input-validation.test.ts for:
    • matching runtime and manifest versions;
    • runtime version 0.0.73 with a 0.0.72 manifest;
    • missing binary;
    • non-zero exit;
    • unparseable version output.
  • Add equivalent Python transaction coverage in test/hermes-mcp-config-transaction.test.ts.
  • Add a Hermes runtime/E2E test in test/e2e/live/rebuild-hermes.test.ts that substitutes a mismatched OpenShell version and proves startup or credential configuration fails closed.

Acceptance criteria

  • TypeScript and Hermes/Python credential-boundary paths verify the actual runtime OpenShell version before applying manifest deny-lists.
  • Exact matches proceed normally.
  • Mismatch, missing binary, command failure, and parse failure are rejected before credentials are written or the affected runtime starts.
  • Unit tests cover both implementations.
  • Hermes runtime coverage proves the check cannot be bypassed by starting an image with a different OpenShell binary.

Activity

  1. added theissue type on Jul 6, 2026
  2. added
    area: securitySecurity controls, permissions, secrets, or hardening
    on Jul 6, 2026
  3. wscurran commented on Jul 6, 2026

    @wscurran
    Contributor
  4. added
    needs: unblockBlocked item needs dependency or decision resolved
    and removed on Jul 9, 2026
  5. cv commented on Jul 9, 2026

    @cv
    Collaborator

    Host-side enforcement is complete via #6261 and #6479: current main validates the selected OpenShell CLI version before MCP credential mutations. The remaining Hermes criterion cannot safely attest the supervisor from inside the workload on pinned 0.0.72, so this is now blocked on an authenticated upstream supervisor-version capability and deferred from v0.0.80.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area: securitySecurity controls, permissions, secrets, or hardeningneeds: unblockBlocked item needs dependency or decision resolved

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions