v1.0.0-rc14
Pre-releaseChanged
-
evm_send_raw_transactionrelay scope is now enforced on the authenticated
path too, not only under keyless writes. The tool is a scoped anchoring
relay: the server decodes each signed transaction and refuses to broadcast
unless its destination is the anchor precompile (ANCHOR_ADDRESS) — other
contracts, externally-owned accounts, native value transfers, and contract
creation are rejected with no broadcast. Previously this check ran only on the
anonymous keyless-write path; the authenticated/self-host path decoded
best-effort and relayed any signed transaction. Now both paths share one gate
(decodeAndScope), so a caller's signature can never be relayed through this
server to move funds or reach an arbitrary contract. The authenticated path
still passes the caller's original bytes through (keyless broadcasts the
canonical re-encode). Behavior change for self-hosters: an authenticated write
to a non-anchor destination — or a signed transaction the decoder cannot parse
— is now rejected by default where it previously broadcast.New escape hatch
MCP_RELAY_ALLOW_ANY(defaultfalse) restores the prior
unscoped best-effort relay on the authenticated path only, for self-host
operators who genuinely need to broadcast non-anchor transactions (registry
deploys, admin ops, exotic tx types). It has no effect under keyless writes
and is a boot error (ErrRelayAllowAnyWithKeyless) if combined with
MCP_KEYLESS_WRITES=true— anonymous writes are always pinned to the
precompile. Reads of any data remain unrestricted. Documented inREADME.md
(Write Architecture + env table),docs/TOOL_REFERENCE.md§16, and
.env.example. -
Privacy Policy revised for the authless architecture, effective 2026-07-14.
The published Policy now describes the Service as it actually runs: no
authentication on any tool, abuse controlled by the on-chain signer address
recovered from each broadcast, and the anchor-precompile-only relay
restriction. The retention schedule in §8 is the one the in-code purge
enforces (shipped in rc13).Validated against the codebase before publication. Corrections made as a
result: §3(c) now discloses themethod_selectorcolumn (the four-byte
public ABI function identifier stored alongside the calldata length);
§3(d)'s IP-logging sentence now matches the code, which logs a caller IP only
on error, authentication-rejection, Origin-rejection, and rate-limit paths
and never on an accepted tool call; §8'sadmin_auditrow no longer refers to
"account closure" (the Service has no user accounts); and §10 no longer claims
an Origin allowlist is enforced on every request, since a request carrying
no Origin header is not rejected on that basis — the DNS-rebinding defence the
MCP specification actually requires.The file is renamed
docs/NVNM_MCP_Privacy_Policy_Jun_2026.pdf→
docs/NVNM_MCP_Privacy_Policy_Jul_2026.pdfto match its new effective date;
the four references inREADME.mdanddocs/TERMS.mdare updated in the same
commit.
Security
- Bumped
golang.org/x/cryptov0.50.0 → v0.54.0 to clear seven Dependabot
alerts (all SSH-package vulnerabilities in that module:VerifiedPublicKeyCallback
permission-skip, client-driven server deadlock, agent-constraint drop on key
forwarding,@revokedauth-bypass, pathological RSA/DSA DoS, certificate-
restriction bypass, and aCheckHostKey/Authenticateserver panic). The
vulnerablex/crypto/sshcode is not reachable from this server — no package
in the module importsx/crypto(go mod whyconfirms it is a transitive-only
requirement viagooseandx/net) — so this is a hygiene bump to keep the
alert page clean ahead of public release, not a fix for an exploitable path.
The upgrade pulled the rest of thegolang.org/x/*family up in step
(net0.53→0.56,sys0.43→0.47,text0.36→0.40,sync0.20→0.22); all
BSD-3-Clause. Vendor tree re-synced;go test -race ./...green.
Removed
-
The opt-in Docker Hub mirror is gone from the image workflow.
image.yml
carried a mirror that, when the repo variableDOCKERHUB_IMAGEwas set,
logged intodocker.iowithDOCKERHUB_USERNAME/DOCKERHUB_TOKENand
re-tagged each GHCR manifest onto Docker Hub. It was never enabled — the
variable was never set, so the steps always skipped — and mirroring has in
practice been done by hand.It was removed rather than left dormant. This repository is headed for public
release, and a workflow step that references a private-registry credential
is a reachable sink for that credential the moment one repo variable is set;
"currently skipped" is a configuration state, not a security boundary.
GHCR is now the sole registry this workflow publishes to, and the workflow
holds no credential for any other.No supply-chain guarantee is lost. The mirror never rebuilt anything — it
re-tagged the same content-addressable digest — so an image mirrored by hand
(docker buildx imagetools create -t docker.io/<org>/nvnm-mcp-server:<tag> ghcr.io/nvnm-chain/nvnm-mcp-server:<tag>) is byte-identical to what the
automated step produced and carries the same Cosign signature over that
digest. Publishing to a second registry is now a deliberate, human act.
Verifying signatures
Each binary is shipped with a Cosign keyless signature (via Sigstore OIDC) and a SHA-256 checksum.
# Verify checksum
shasum -a 256 -c nvnm-mcp-server-v1.0.0-rc14-<os>-<arch>.sha256
# Verify Cosign signature
cosign verify-blob \
--certificate nvnm-mcp-server-v1.0.0-rc14-<os>-<arch>.cert.pem \
--signature nvnm-mcp-server-v1.0.0-rc14-<os>-<arch>.sig \
--certificate-identity-regexp 'https://github.com/NVNM-Chain/nvnm-mcp-server/.*' \
--certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \
nvnm-mcp-server-v1.0.0-rc14-<os>-<arch>