CSA MCP Security framework mapping
The Cloud Security Alliance MCP Security Working Group publishes the only public hardening framework that addresses Model Context Protocol servers and the wider class of components that AI agents call. Its structure splits controls into four tiers — foundational, deployment, operational, advanced — and provides a vocabulary that procurement, compliance, and security teams already use.
This page maps each control area to the concrete capability inside ACT that delivers it. It is honest about what is shipped today, what is planned, and what is deliberately out of scope. For the framework itself, see the WG repository.
Foundational
Section titled “Foundational”Provenance verification
Section titled “Provenance verification”| Status | Shipped |
| ACT capability | Keyless cosign signing via GitHub OIDC; source repository pinned in every artifact |
Every component published under actpkg.dev/library is signed in its upstream CI with
keyless cosign over GitHub’s OIDC token — no long-lived signing key exists. The signature
binds the artifact’s OCI manifest digest to the workflow identity that produced it (a workflow
in github.com/actpkg/<component>), and is attached to the artifact in the registry. Verify
before you deploy:
cosign verify actpkg.dev/library/sqlite@sha256:<digest> \ --certificate-identity-regexp '^https://github\.com/actpkg/' \ --certificate-oidc-issuer https://token.actions.githubusercontent.comThe component’s source repository URL is also recorded twice — as the OCI
org.opencontainers.image.source annotation, and inside the act:component custom section,
which the host reads without executing the component.
Code integrity auditing
Section titled “Code integrity auditing”| Status | Partial — pinned toolchains and inspectable artifacts shipped; verified reproducibility, LLM-audit and dependency scanning planned |
| ACT capability | Pinned build toolchains; CNCF Wasm OCI Artifact manifests via act-build push |
act-build push emits a CNCF Wasm OCI Artifact
conformant manifest with a config blob carrying architecture, os, layerDigests, and the
component’s own exports and imports — so registry-side tooling can audit what an artifact claims
to do without pulling the layer. Component builds pin their toolchains (rust-toolchain.toml,
and a pinned container image for the harder language targets).
LLM-driven code audit, dependency vulnerability scanning, and SBOM publication are on the roadmap.
Deployment
Section titled “Deployment”Runtime isolation
Section titled “Runtime isolation”| Status | Shipped |
| ACT capability | wasmtime component sandbox; declared capability imports |
Components run inside a wasmtime virtual machine that enforces memory safety and instruction-level isolation. This is strictly stronger than container isolation: a wasm component cannot make a syscall that wasn’t explicitly imported through WASI. There is no kernel attack surface to escape — the component physically cannot express the operation. See Policy & sandbox for the runtime-grant side of the model.
Traffic mediation
Section titled “Traffic mediation”| Status | Shipped |
| ACT capability | wasi:http allow/deny lists; DNS-layer CIDR deny; per-redirect re-check |
Every outbound HTTP request is gated by host policy along five axes: host, scheme, method, port, and DNS-resolved IP. CIDR-based deny lists block private ranges and metadata services (169.254.169.254/32) before they leave the sandbox. Each hop of a redirect chain is re-checked against the same policy — a 302 to a denied host fails mid-chain instead of silently succeeding. See wasi:http policy.
Operational
Section titled “Operational”Secrets management
Section titled “Secrets management”| Status | Shipped |
| ACT capability | Credentials travel in session args, never in per-call metadata; a host credential store the agent cannot read |
Credentials never live in per-call metadata, where every agent invocation would see them. A
stateful component publishes the argument schema it expects via
get-open-session-args-schema,
receives its credentials once at session open, and hands back an opaque session id — that id
is all the agent ever handles afterwards. Session args are also the one thing the audit trail
never records, even under --audit-args.
Operators keep values in a host-side credential store rather than in config or environment
variables: act secret set writes one, act login prompts for whatever a component declares in
its [[std.credentials]] entries, and neither command will print a stored value back — there is
deliberately no act secret get. See the auth design rationale.
Input validation
Section titled “Input validation”| Status | Shipped, with one documented gap |
| ACT capability | Host-side JSON Schema validation of tool arguments and session args, before the guest |
Arguments reaching a component are composed by a language model reading a schema, which makes them
untrusted input in the ordinary sense. The host validates them against the component’s own
declared parameters-schema — and session args against get-open-session-args-schema — before
the component is reached. A mismatch is refused, and the component never sees the call:
Error: std:invalid-args: arguments do not match the schema for 'query':- at '/sql': want string, but got numberA guest-authored schema’s $ref is never fetched: the validator resolves only registered
resources and none are registered, so a schema cannot become an outbound request the component
never declared wasi:http for.
Observability & logging
Section titled “Observability & logging”| Status | Shipped |
| ACT capability | Always-on audit trail: resolved policy, every capability decision, one record per tool call |
Every run emits an audit trail on stderr. It opens with the artifact digest and the policy each capability actually resolved to, records each capability decision as it is made — with the reason — and closes each tool call with a rollup:
audit: actpkg.dev/library/sqlite sha256:cb7715 │ act:credentials=deny wasi:filesystem=allowlist wasi:http=deny wasi:sockets=denyaudit: ✓ allow wasi:filesystem write /data/app.sqlite mode:allowlist under /data/**audit: ✗ deny wasi:filesystem read /dev/urandom outside ceiling mode:allowlistaudit: ● query ok 0ms args:1e91dd req:005ea7 session:sqlite_0Two properties matter for an evidentiary log. It is redaction-aware by default: tool
arguments are recorded as a digest, not a value, and session args — which is where ACT puts
credentials — are never recorded at all. --audit-args swaps the digest for full values and warns
that it can expose secrets. And it is not a logging level: the trail is filtered independently
of RUST_LOG, so raising or silencing application logs cannot silence it. Only --no-audit, or
[audit] enabled = false in the config file, turns it off; [audit] detail selects rollup
(default) or full.
Guest-emitted telemetry is kept on a separate channel and is never merged into the audit trail — a component cannot write to its own audit record.
Backup & versioning
Section titled “Backup & versioning”| Status | Shipped (delegated to OCI registry) |
| ACT capability | Immutable OCI tags; content-addressable retrieval by digest |
Components are referenced by actpkg.dev/library/<name>:<version> and resolvable by digest (@sha256:...). The host caches pulled components by reference at ~/.cache/act/components/, so the running artifact is always traceable to a registry-tagged version.
Advanced
Section titled “Advanced”Policy enforcement
Section titled “Policy enforcement”| Status | Shipped |
| ACT capability | Capability ceiling (build-time declaration ∩ runtime grant) |
This is ACT’s signature control. Every component declares the capabilities it requires in its act.toml ([std.capabilities."wasi:filesystem"], [std.capabilities."wasi:http"], etc.); the operator grants what they’re willing to give at run time. The effective policy is the intersection: a permissive operator cannot escalate past the component’s stated intent, and a lazy component cannot silently reach past the operator’s grants. See Policy & sandbox.
Runtime consent
Section titled “Runtime consent”| Status | Shipped for physical capabilities; semantic-action consent specified, not yet implemented |
| ACT capability | Ask-by-default prompting with a per-session decision cache and fail-safe deny |
A capability ceiling answers what may this artifact reach at all. It does not answer should
this particular action happen now — so the default policy mode is ask: the first time a
component touches a granted capability, the operator is asked, and the answer is cached for the
session. The prompt goes to the TTY for an interactive act call, or to the connected MCP client
via MCP elicitation when running under act run --mcp. Where there is no channel to ask on, the
answer is deny — a headless run cannot be silently escalated by leaving the mode at ask.
This defends against a different adversary than the ceiling does. The ceiling stops a rogue component — an artifact that does something other than what it claims — because the host intercepts the boundary and the component simply cannot reach what it wasn’t granted. Consent addresses a rogue agent: a mistaken or prompt-injected model driving a component that is behaving exactly as documented.
That second adversary has a gap the physical boundary cannot close. DROP DATABASE analytics
travels over a socket the operator already granted; a prompt injection reaches a browser over an
already-granted HTTP session. The host sees permitted bytes on a permitted channel.
act:[email protected] closes it
by inverting the initiative: the component names the class of action it is about to take
(db:drop), and the host applies that class’s policy — the same grants, modes, and audit
trail as any physical class. It is normatively specified and, like act:credentials, is a host
import a component opts into. The host does not implement it yet; today a component that wants
this enforces its declared semantic classes itself, and operators gate them with
--deny db:drop.
Payments / wallet security
Section titled “Payments / wallet security”| Status | Experimental preview |
| ACT capability | openwallet component — reference implementation against Open Wallet Standard |
The openwallet component implements OWS via the upstream ows-core and ows-signer crates. Distributed as a wasi:filesystem-bounded sandboxed component with declared capabilities. Marked as preview/demo, not a production wallet — see the component README. (OWS at openwallet.sh is independent from the OpenWallet Foundation at openwallet.foundation; the latter focuses on verifiable credentials.)
Lifecycle management
Section titled “Lifecycle management”| Status | Shipped |
| ACT capability | act:sessions/session-provider — open-session / close-session |
Stateful components opt into act:[email protected], a three-function WIT interface that hands explicit lifecycle control to the host. The host keeps the wasm instance alive while sessions are open and closes whatever’s still open before tearing the instance down. Auth, parsed-spec caching, and live-connection state all live behind this boundary.
Roadmap
Section titled “Roadmap”The framework areas marked partial above translate to concrete in-flight work:
- Host-side signature verification —
actpulls and runs without checking the cosign signature today; gating execution on verification is in-flight. act:consentin the host — the semantic-action interface is specified and unimplemented; until it lands, semantic classes rest on the component enforcing its own declarations.- Verified reproducible builds — rebuild-and-diff in CI, so byte-identical output becomes a checked property rather than an aspiration.
- LLM-driven code audit + dependency vulnerability scanning integrated into the
actpkg.devcuration pipeline. - SBOM publication alongside every component artifact.
- Capability attenuation — issuing a strict sub-policy of the granted ceiling to a specific agent session.
Engage
Section titled “Engage”Engineering and procurement contact for the framework itself runs through the WG, not through ACT:
- WG home
- WG GitHub organisation — discussions, vulnerability database, audit database
- WG bi-weekly meeting calendar
If you’re evaluating ACT against this framework for a procurement or compliance review, the act-spec repository is the normative source for every claim on this page. Issues, “this looks like what I’d want for X but Y is missing” reports, and gaps you spot in the mapping above are welcome at github.com/actcore/act-spec/discussions.