Skip to content

v2.4.1

Choose a tag to compare

@github-actions github-actions released this 26 Aug 03:26
· 112 commits to main since this release
v2.4.1
4f81744

Security

  • gateway.update_server no longer installs and executes a registry package
    derived from a misparsed command.
    The update probe is built from the parsed
    package name — npx -y {name}@latest --help — and npx -y installs without
    prompting. A server configured as npm run mcp names a script in the
    local package.json, not a registry package, but the parser returned it as
    one, so pmcp fetched and ran whatever occupied that name on the public
    registry. Short generic script names (run, start, dev, mcp) are
    exactly the kind that can be registered and waited on.

    npm package detection is now an allowlist: only exec, x, install,
    i, add and dlx put a registry package in the next position. Every other
    subcommand — run, start, test, stop, restart, run-script, init,
    create — and every misspelling of one reports no recoverable package
    identity
    , and update_server refuses on that before constructing any
    probe. That is the same rule the identity gate follows: cannot confirm, so do
    not act on a guess.

    An allowlist rather than a denylist of script runners, because the
    consequence of being wrong is asymmetric: failing closed costs only the
    ability to auto-update a server launched by an unusual form, while failing
    open costs arbitrary package execution. (npm create foo also shows why
    synthesising a name is not safe: npm resolves it to the package create-foo,
    so foo names a different package than the one npm would run.)

    Reaching this required a server configured with an affected form and an
    operator invoking gateway.update_server on it; it was not remotely
    triggerable. npx -y run still resolves normally — the refusal is scoped to
    npm subcommands whose operand is not a package, not to those names.

Fixed

  • Two different packages no longer share one identity for common docker and
    npm command forms.
    2.4.0's identity gate decides whether a cached
    description still describes the configured package by comparing the name
    detect_package_type returns, so a name that was stable across two different
    packages was read as a positive confirmation — and the freshness
    short-circuit went on serving the wrong package's tool descriptions.

    Two independent causes, both closed:

    • Docker references split on the first :, so registry:5000/old-image
      and registry:5000/new-image both resolved to the image registry — the
      registry host, not an image at all. A colon only introduces a tag when it
      appears in the final path segment; before the last / it is a registry
      host:port. The correct rule already existed in this module as
      _docker_image_tag, so the fix adds its paired complement rather than a
      second, divergent implementation of the same rule.
    • npm subcommands were taken as the package name, so npm exec old-pkg
      and npm exec new-pkg both resolved to exec. A leading subcommand
      (exec, x, run, install, i, add, create, dlx) is now skipped
      — once, and only for npm, so npm install i still finds the real package
      i and npx -y exec still finds a package genuinely named exec.

    Affected servers refresh once. A docker server on a host:port registry
    or an npm exec server now has a different package identity than the one
    its cache entry recorded, so that entry fails the identity check once and is
    regenerated — the same one-time migration 2.4.0's package_type addition
    caused.

  • A docker digest is now recognised as the pin it is. gateway.update_server
    read the tag from the whole reference, so img@sha256:abc reported a pin of
    abc — a fragment of the digest presented as a version — and
    img:1.2@sha256:abc reported 1.2@sha256:abc instead of a usable value. A
    digest is the tightest pin docker offers, so it is now reported whole and
    checked before the tag: img@sha256:…, img:1.2@sha256:… and
    img:latest@sha256:… all report the digest. That last form matters — a
    latest tag must not discard a real digest pin. Previously such a server
    could be "updated": pmcp would pull image:latest, restart the unchanged
    digest-pinned configuration, and record the registry's newest digest while
    still running the old immutable image.

  • A version pin on an npm exec server is now detected. Pin detection
    shares its argument scan with package detection, so it inherited the
    subcommand bug: npm exec pkg@1.2 scanned to exec, which carries no
    version suffix, and a real pin was reported as unpinned.

    This narrows #180 rather than closing it. Package identity
    is still collapsed wherever a flag's value is taken as the package name —
    docker run --env-file X <image>, docker run --mount <spec> <image>,
    npm exec --package=<pkg>, and the uvx/pip/cargo equivalents. Those are
    tracked on #182, and #183 tracks a related but
    more serious consequence of a misparse.