Skip to content

security: extension capabilities are declared but never enforced #397

Closed

Description

@codeforester

Problem

ExtensionDescriptor.capabilities is parsed from entry-point extras and exposed publicly, but
nothing in the package ever reads it to make a decision. It looks like a permission model and grants
nothing.

_descriptor_from_entry_point() collects base-cli-cap-* extras into a sorted tuple
(lib/python/base_cli/extensions.py:364-370), and docs/extensions.md:41-51 tells authors to
"Declare the SDK version and capabilities in the entry-point extras". api_version is enforced —
ExtensionCompatibilityError is raised in load() when it is unsupported (line 236-237) — which
makes the neighbouring unenforced field more misleading, not less: an adopter reasonably infers that
declaring base-cli-cap-network means something.

A secondary weakness in the same area: _allowed() (lib/python/base_cli/extensions.py:312-319)
admits a descriptor if the allowlist contains the bare name, the group:name key, or the
distribution name. Allowlisting a bare name therefore admits that name from any group and any
distribution, and allowlisting a distribution admits every entry point it ships — including ones
added in a later release of that distribution. For an allowlist, which exists to be a trust
boundary, the loosest match winning is the wrong default.

Verified evidence

Reviewed 2026-09-30 at a58ec109349fa3f3d03eae5b0de078b39ea361a2.

$ grep -rn "capabilities" lib/python/base_cli/ docs/extensions.md
extensions.py:109:    capabilities: tuple[str, ...] = ()
extensions.py:364:    capabilities = tuple(
extensions.py:379:        capabilities=capabilities,
docs/extensions.md:41:Declare the SDK version and capabilities in the entry-point extras. The
docs/extensions.md:51:`ExtensionDescriptor.api_version` and `.capabilities` expose this metadata.

Three references in the package, all construction or storage; no comparison, no filter, no gate.

Proposal

Pick one and make it explicit:

  1. Enforce them. Give ExtensionDiscovery a supported_capabilities / required_capabilities
    parameter, refuse to load an extension declaring a capability the host has not granted, and raise a
    typed error naming the capability — mirroring how api_version already works. Note honestly in the
    docs that this is declarative: a loaded Python extension runs in-process with full privileges, so
    the gate expresses intent and enables audit, it does not sandbox.
  2. Demote them. Document capabilities as informational metadata only — useful for inventory and
    for the CLI catalog work in [platform] Define signed CLI Catalog ingestion and governance boundaries #277 — and say plainly that it grants and restricts nothing.

Separately, tighten _allowed(): make group:name the canonical allowlist form, treat a bare name as
matching only within an explicitly requested group, and require distribution entries to be written as
something unambiguous such as dist:<name>. Document the precedence.

Acceptance criteria

  • capabilities is either enforced with a typed refusal and tests, or documented as
    non-enforcing metadata in docs/extensions.md.
  • If enforced, the documentation states clearly that it is not a sandbox.
  • Allowlist matching semantics are documented, and a test asserts a bare-name entry does not admit an
    entry point from an unintended group or distribution.
  • docs/security-threat-model.md reflects whatever the extension trust boundary actually is.

Non-goals

  • Do not build extension sandboxing or subprocess isolation here.
  • Do not change EXTENSION_API_VERSION or the entry-point group names.

Activity

  1. added this to the v1.0.0 milestone on Sep 30, 2026
  2. added
    enhancementNew feature or product improvement
    securitySecurity hardening or vulnerability work
    on Sep 30, 2026
  3. self-assigned this
    on Sep 30, 2026
  4. moved this from Backlog to In Progress in base-clion Oct 22, 2026
  5. moved this from In Progress to In Review in base-clion Oct 22, 2026
  6. codeforester commented on Oct 22, 2026

    @codeforester
    ContributorAuthor

    Implementation evidence is in PR #462: #462

    Capabilities are now explicitly informational metadata, allowlists require fully qualified group:name or dist:distribution entries, and exact matching is covered by tests and security documentation. The issue-branch policy was also repaired by retaining only the security category label; required hosted checks are now green. The issue remains In Review pending review/merge.

  7. codeforester commented on Oct 23, 2026

    @codeforester
    ContributorAuthor

    Review follow-up completed in PR #462. Distribution allowlists now use exact installed metadata spelling and a precomputed approved set; a case-variant regression test and documentation were added. Commit: 10e1f7d. Focused and full pytest pass locally; all review threads are resolved.

  8. moved this from In Review to Done in base-clion Oct 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

securitySecurity hardening or vulnerability work

Type

No type

Projects

  • Status
    Done

Relationships

None yet

Development

No branches or pull requests

Issue actions