Operating Local MCP Servers Safely
This guide explains principles for safely adopting, developing, and operating local MCP servers (mostly stdio) that run on a developer machine. The protocol-level threat model, such as OAuth and token handling, is covered in MCP Security Best Practices - Attacks and Mitigations. This document targets a different threat model: running someone else's code on your own machine.
1. What This Document Covers
- The privileges of a local server, and the stdio trust model
- Threats to consider
- Whether you need to run it locally at all
- Checking provenance before installation
- Treating tool definitions as untrusted input
- Consent for launch commands (SEP-1024)
- Running in an isolated environment
- Isolating credentials
- Restricting file system access
- Controlling network egress
- Protecting localhost HTTP servers (DNS rebinding and Origin validation)
- Notes for server developers (handling stdout, path traversal)
- Management in an organization
The privileges of a local server, and the stdio trust model
A local MCP server is not a plugin running inside a sandbox provided by the protocol. It is an ordinary OS process launched by the host application. It can therefore touch the following.
With stdio, the client launches the server as a child process and communicates over stdin and stdout. This design assumes that the client and the stdio server share a single trust domain. The two run side by side with the same privileges, and the server can already execute code on the machine the moment it is launched. Because the transport has no boundary to defend, neither the protocol nor the SDK protects one side from the other. If you want to run a server with reduced privileges, you build that boundary yourself with a container, sandbox, or VM.
The real safety decisions are made before launch: what you install (provenance) and how you run it (isolation). In addition, every configured server shares the same model context. A malicious server can influence how the tools of all other servers are used, so each server you add also widens the attack surface that the other servers face.
Threats to consider
- Malicious servers: typosquatted package names, lookalike repositories, and new publishers who take over abandoned projects. They behave as advertised while exfiltrating environment variables and files
- Over-collecting servers: a legitimate server collects environment variables, files, and traffic beyond what its job needs. Prompt injection through untrusted content can also make an honest server do the same using the privileges it was given
- Compromised dependencies: the server's author is honest, but one of its dependency packages has been compromised in a supply chain attack
- Poisoned tool catalogs: tool names and descriptions are instructions that the model reads. A server can hide instructions there and steer the agent, including how the tools of other servers are used (tool poisoning, tool shadowing). Rug pulls, which rewrite definitions after approval, also exist, so consent at install time and package pinning alone cannot protect this surface (see AI Agent-Specific Threats - Prompt Injection and Tool Poisoning for details)
- Vulnerable servers and bridges: legitimate, unmodified components can also be an entry point. A local bridge that connects a stdio client to a remote server has been found to contain a critical flaw that triggers just by connecting to a malicious endpoint. A local development tool listening on a port has also been attacked directly from a web page
Out of scope are attackers with physical access to the machine, targeted nation-state attacks, and protocol-layer attacks.
First, here is the fact that underlies every mitigation. No check can prove in advance what a server will do. A readable repository, signatures, an SBOM, and a curated list tell you whom you are trusting, but not whether that trust is warranted. Unless you audit and build every release yourself, you cannot verify behavior beforehand.
The mitigations therefore follow one principle: treat a third-party local server as untrusted code that has only the privileges you give it, and minimize those privileges. Vetting lowers the probability of a bad trust decision, and containment determines the cost of one.
Whether you need to run it locally at all
The cheapest way to shrink the blast radius is to not create one. Before installing a server as a local process, ask what it needs from the machine. Reading the working tree, operating local tools, and accessing hardware are reasons to run locally. A server that merely wraps a remote API gains nothing from running locally.
- If a remote version exists, use it. A server offered over Streamable HTTP runs no code on your machine, uses the protocol's authorization flow instead of placing tokens in a local config file, and gets fixes distributed from one place. The protocol's threat model applies to this case
- If a third-party server is offered only as a stdio process even though it needs no local access, ask why. It may just be the easier path for the author, but it is also a path through which malicious and over-collecting servers arrive
- Some functionality works only as a local process. In that case, apply all of the measures below
When in doubt, for a server that needs none of files, local tools, or the local network, use the remote version and skip the local installation.
Checking provenance before installation
Being listed in a registry is not an endorsement. Docker Hub, ghcr.io, npm, PyPI, and NuGet host almost anything. Popularity and a plausible name guarantee neither safety nor freshness. Even curated MCP catalogs describe their review as best effort and do not take responsibility for what you run.
Before installing a server, check the following.
- Identify the publisher: can you tie the package to a source repository and to a real maintainer or organization? Does the repository show recent, plausible activity?
- Verify the package name exactly: typosquatting is the cheapest attack. Confirm that it is the package the documentation actually points to and not a lookalike
- Pin the version: install a specific version rather than
latest, so that a future compromised release does not arrive through auto-update. Pair pinning with a habit of planned updates. When a vulnerability is disclosed in what you pinned, pinning leaves you vulnerable - Know what pinning covers: pinning the package version with a launcher such as
npxoruvxpins only the top-level package, and transitive dependencies are normally resolved fresh at install time. This is exactly where a compromised dependency gets in. Pinning a container image by digest (image@sha256:...) pins the entire dependency tree - Prefer packages with provenance metadata: signed artifacts, build attestations, and an SBOM let you verify who built it and what is inside. They also tell you which version of which MCP SDK is used, which helps when a vulnerability is disclosed in an SDK
To go further, do not just check that signatures and attestations exist; actually verify them (Sigstore tools, registry verification features). Do not trust a published SBOM; generate one yourself from the artifact (Syft or Trivy). With a registry or runtime that can verify signatures at execution time, you can turn provenance from an install-time check into a continuous one.
When in doubt, install only servers whose source you can read and whose publisher you can identify, and pin the version exactly.
Treating tool definitions as untrusted input
Installing a server is not the last trust decision. At runtime, the server sends tool names and descriptions to the client, and the model reads them as instructions. Pre-install vetting does not cover this injection surface.
- Read the tool list before relying on a server. Many clients can display each tool's description. MCP Inspector enumerates every tool a server exposes without going through a model. If a description contains instructions unrelated to the tool's purpose, remove that server
- Choose a client that pins tool definitions. Some clients record definitions at first approval and ask again when they change. The protocol does not require this, so it matters as a property when choosing a client
- Keep the number of servers small. Every configured server shares the model context, so each addition widens the attack surface the other servers face
When in doubt, install a few servers, read the tool descriptions once, and choose a client that re-confirms when definitions change.
Consent for launch commands (SEP-1024)
If a client can install a local server with one click, it MUST implement an appropriate consent mechanism before running the command (SEP-1024). The client does the following.
- Displays the command to be executed in full, without truncation (including arguments and parameters)
- States clearly that this is a potentially dangerous operation that runs code on the user's system
- Requires the user's explicit approval before proceeding
- Lets the user cancel the setup
In addition, the following extra checks and guardrails are recommended for clients (SHOULD).
- Highlight dangerous command patterns (
sudo,rm -rf, network operations, and file system access to unexpected directories) - Show a warning for commands that access sensitive locations (home directory, SSH keys, system directories)
- Warn that the MCP server runs with the same privileges as the client
- Run the server's command in a sandbox with minimal default privileges
- Restrict the server's access to the file system, network, and other system resources
- Let the user explicitly grant additional privileges (specific directories, network) when needed
- Use technologies suited to the platform, such as containers, chroot, and application sandboxes, and keep the sandbox up to date against new vulnerabilities
A consent dialog helps only users who know what to look for. The following sections cover what to look for.
Running in an isolated environment
Process isolation is the most effective measure in this document. It turns "this server can read my SSH keys" into "this server can read an empty directory", and it works against all the threats above at once, even when provenance checks fail.
- Basic: run third-party servers in a container (Docker or Podman) that mounts no volumes other than what is needed. The stdio transport works as is, and the client communicates with the container's stdin and stdout just as it would with a bare process
- Alternatives: a lightweight VM dedicated to development, or the OS's process sandbox features. Some MCP-oriented runtimes and client integrations wrap servers in containers automatically. What matters is the pattern, not the tool
A container is not an unbreakable boundary, but it removes the default state of having access to your environment, files, and keychain. Common attacks rely on exactly that.
To go further, restrict system calls with a seccomp profile and restrict reachable resources with AppArmor or SELinux (often just enabling the distribution's defaults). You can also run in a microVM or under a separate user account, and combine that with the network controls below so that the sandbox cannot exfiltrate even the small amount of information it can see.
When in doubt, run every third-party server in a container that mounts nothing except the directory it works on.
Isolating credentials
A locally launched server may inherit the environment of the process that launched it. If your shell profile exports cloud credentials or API tokens globally, every server you run can read them.
- Pass secrets per server, not globally. Instead of exporting them in your shell profile, use the per-server environment variable settings in the client's config file so that each server sees only its own credentials
- Narrow token scopes. Issue each server a token with the smallest scope that works (for example, a fine-grained access token limited to one repository rather than an account-wide token). If it leaks, the damage is limited and the token can be revoked
- Do not keep long-lived secrets in plaintext config. Client config files are in known, predictable locations on disk. If the client supports it, use the OS secret store (Keychain on macOS, Credential Manager on Windows, freedesktop Secret Service on Linux)
- Files count as credentials too. Directories such as
~/.sshand~/.awsare credentials on disk. What actually keeps servers away from them is the process isolation described in the previous section
To go further, use short-lived credentials issued at launch by a secret manager or broker instead of static tokens, and when you decide to remove a server, rotate whatever that server held. When in doubt, pass narrowly scoped tokens through per-server configuration, and do not reuse a broad personal token across multiple servers.
Restricting file system access
Many useful servers legitimately need file access. The question is how far.
- Give the narrowest root that works. For file-oriented servers, pass a specific project directory explicitly through server configuration or a tool parameter. Do not pass the home directory
- Prefer read-only. For a server that only reads code or documents, mount or allow the directory read-only
- Be suspicious of broad scope. A server that requests a broad root directory for a narrow job is overreaching. Give it a narrow directory or choose another server
A configuration-level allowlist is a cooperative boundary. Well-behaved servers honor it, but the protocol does not stop a malicious or compromised server from reading whatever its process can reach. Treat it as a guardrail for honest servers, and get enforcement from sandbox or container isolation, where only the permitted directories exist as a file system.
Note that Roots is deprecated in the 2026-07-28 version. Control the allowed directories through configuration or tool arguments. When in doubt, allow one project directory, read-only.
Controlling network egress
Exfiltration needs an exit. A local process normally has unrestricted outbound traffic, which turns over-collection or compromise directly into data leakage.
- Know where the server is supposed to communicate. A server that wraps a single API has a short, predictable set of destinations. Traffic to any other destination is a signal worth investigating
- Deny the network if it is not needed. A server that works only with local files and tools does not need the network. With a container, a single flag (
--network=none) does it - Filter the rest. For servers that need egress, restrict outbound traffic to expected destinations with a firewall that narrows outbound traffic or an egress proxy with a domain allowlist, and log out-of-scope attempts
Egress is not the only network issue. Local MCP components that listen on a port (bridges to remote servers, development tools, locally hosted HTTP servers) can be reached by other local processes, and also by websites through the user's browser. Binding to 127.0.0.1 is not an authentication boundary. These need real authentication and Origin validation, and should be updated promptly when vulnerabilities are disclosed.
To go further, give each server its own egress allowlist at a proxy and raise an alert on out-of-scope destinations, because an unexpected egress is often the first sign that something in this document has been breached. When in doubt, run without a network unless a need is shown, and know which destinations the remaining servers reach.
Protecting localhost HTTP servers (DNS rebinding and Origin validation)
When a locally running MCP server listens over HTTP (Streamable HTTP), a malicious web page can use DNS rebinding to send requests to that server, using the user's browser as a foothold. The specification requires Streamable HTTP servers to do the following.
- Validate the
Originheader on all connections (MUST). IfOriginis present and invalid, respond with HTTP 403 Forbidden - When running locally, bind only to localhost (127.0.0.1), not to
0.0.0.0(all interfaces) (SHOULD) - Implement proper authentication for all connections (SHOULD)
Without these, an attacker can interact with a local MCP server from a remote website. If local use is intended, server developers should prevent use by unauthorized processes as follows (SHOULD).
- Use the stdio transport and limit access to the MCP client only
- If using the HTTP transport, restrict access. For example, require an authorization token, or use inter-process communication (IPC) such as a Unix domain socket with restricted access
Notes for server developers
There are things that the authors of local servers must also do.
- Do not pollute stdout: a stdio server MUST NOT write anything to stdout other than valid MCP messages. Logs go to stderr (MAY). A debugging
print, or a logger that writes to stdout by default, not only breaks the protocol but also mixes its content into the communication. See Testing and Debugging MCP for details on debugging and logging - Do not log credentials: do not write tokens received through environment variables, or secrets contained in tool arguments, to stderr or files
- Prevent path traversal: a file-oriented server confines the paths in tool arguments to inside the permitted directory. The reliable way to block escapes via
..and symbolic links is to use OS features rather than string checks (see the code example) - Run with minimum necessary privileges: do not run as root, and narrow file and network capabilities
- Provide artifact provenance: publish version-pinned releases, signatures, and an SBOM so that users can verify them
- Do not expose local bridges or development tools over HTTP; if you do, add authentication
Management in an organization
For IT, security, and platform administrators, the problem is different: many machines, many users, and servers that arrive without administrator involvement. The following two facts are the premise.
- A local MCP server is ordinary software that users install: the protocol cannot inventory, patch, or contain processes on machines you do not manage. This is existing endpoint and software management, with a new kind of package
- You are not consulted in advance: assume that users install servers the same way they install editor extensions
A practical starting point is as follows.
- Define approved sources: publish a short allowlist of vetted servers (version-pinned) and the criteria a new server must meet (an identifiable publisher, readable source, provenance metadata, an SBOM). Make the approved path easier than the alternatives
- Decide the default execution environment: document isolation rather than leaving it to each user's initiative, for example "third-party servers run in a container that does not mount the home directory"
- Centralize what does not need local access: a server that only wraps a SaaS API does not need to run on everyone's laptop. With a centrally managed remote deployment, you can patch, audit, and control one instance instead of hundreds
- Inventory continuously: client config files are in known locations on each platform. If you collect them with endpoint management tools, you can always answer who runs which version from which source
- Keep an audit trail: on managed machines, record which tool of which server was used and when. You can reconstruct what a compromised server actually did, rather than inferring it from its privileges
- Prepare for organization-wide incidents: when a vulnerability is found in a widely used local server (or an SDK within it), identify all instances (inventory), block egress at the proxy or firewall, rotate every credential the configuration handed over, and distribute the fixed pinned version through the approved path. An SBOM lets you answer "which machines run something built with an affected SDK version" in minutes rather than days
- Be aware of the regulatory context: software supply chain regulations such as the EU Cyber Resilience Act tend to require exactly these practices, such as SBOMs, update procedures, and vulnerability handling
When in doubt, start with an organization-wide inventory of client configuration and a short allowlist of approved servers, and treat anything that appears in neither as unapproved software.
2. Defense Layers for Local Servers
| Layer | Measure | Owner |
|---|---|---|
| Placement | Use the remote version if one exists. Ask whether local is needed | User / Administrator |
| At install | Full display of the command and explicit consent, checking provenance and publisher | Client / User |
| Artifacts | Version pinning (digest for containers), signing, SBOM | Server developer / User |
| Tool definitions | Review the list, re-approve on change, minimize the number of servers | Client / User |
| At runtime | Containers, sandboxes, least privilege | Client / User |
| Credentials | Per-server environment variables, narrowly scoped tokens, secret stores, keep out of logs | User / Server developer |
| Files | Read-only narrow directories, enforce through isolation | User / Server developer |
| Network | Block if not needed, egress allowlist if needed | User / Administrator |
| Communication | stdio, or authenticated localhost or IPC, Origin validation | Server developer |
| Organization | Approved list, inventory, audit logs, incident response | Administrator |
3. Common Pitfalls for Developers
Assuming approval of the consent dialog means it is safe
Consent is the point where you see the full command and decide that it may run. Reading the command does not reveal the contents of the package or the behavior of its dependencies. Consent is no substitute for provenance checks and isolation.
Using npx -y package-name as is
If you do not pin the version, the latest one is installed on every run, and a future compromised release arrives automatically. Even if you pin the version, transitive dependencies are not pinned. To pin down the dependency tree as well, pin the container image by digest.
Pinning and never updating
Pinning a version also means continuing to use a vulnerable version after a vulnerability is disclosed. Set a routine for updates and subscribe to vulnerability advisories.
Exporting tokens in the shell profile
Every server launched from that shell can read every token. Use per-server environment variable settings and pass only what is needed.
Thinking a configuration allowlist protects files
A directory restriction in configuration is a cooperative boundary. A malicious server can ignore it. Enforce it with a sandbox or container mounts.
Assuming binding to 127.0.0.1 is safe
It can be reached by other processes on the same machine and by web pages in the browser. Authentication and Origin validation are required.
Debugging a stdio server with print
Output to stdout is interpreted as MCP messages. It can prevent the client from connecting or corrupt responses. Write logs to stderr.
Preventing path traversal with string checks
Checking whether a path contains .. is defeated by symbolic links and encoding tricks. Use the features provided by the OS or libraries that confine access to inside a directory.
Leaving unused servers in place
Unused servers only add attack surface. Remove them from the configuration and rotate the credentials you had given them.
4. Code Examples
Install with a pinned version
# npm: pin the version of the top-level package (transitive dependencies are not pinned)
npx -y @example/[email protected]
# Python: pin the version with uvx
uvx example-mcp-server==1.4.2
# Container: pinning by digest pins the entire dependency tree
docker pull ghcr.io/example/mcp-server@sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
Check provenance and the SBOM
# Verify npm registry signatures and provenance attestations (applies to packages installed in the project)
npm audit signatures
# Do not trust a published SBOM; generate one yourself from the artifact
syft ghcr.io/example/mcp-server@sha256:0123... -o spdx-json > sbom.spdx.json
# Scan for vulnerabilities
trivy image ghcr.io/example/mcp-server@sha256:0123...
Check the tool list without going through a model
# Use MCP Inspector to read the descriptions and arguments of the tools the server exposes
npx @modelcontextprotocol/inspector
Launch in an isolated container (stdio)
Run with no network, a read-only root file system, and only one project directory mounted read-only. Keeping stdin open with -i lets the container communicate with the client over stdio as is.
docker run --rm -i \
--network=none \
--read-only \
--cap-drop=ALL \
--security-opt=no-new-privileges \
--user 65532:65532 \
--memory=512m --pids-limit=128 \
-v "$PWD/docs:/workspace:ro" \
ghcr.io/example/mcp-fs-server@sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef \
/workspace
Pass credentials per server in the client configuration
In the client's config file (mcpServers), specify the command that launches the container and the per-server environment variables. If you pass only the name without a value, as in -e GITHUB_TOKEN, the value is inherited from the env setting and is not written in plaintext to the config file or arguments. For a server that needs the network, remove --network=none here and restrict egress separately.
{
"mcpServers": {
"github": {
"command": "docker",
"args": [
"run", "--rm", "-i",
"--cap-drop=ALL",
"--security-opt=no-new-privileges",
"-e", "GITHUB_TOKEN",
"ghcr.io/example/github-mcp-server@sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
],
"env": {
"GITHUB_TOKEN": "${GITHUB_MCP_TOKEN}"
}
}
}
}
Whether environment variable expansion such as ${GITHUB_MCP_TOKEN} is supported depends on the client. If it is not, use a mechanism that references the OS secret store, or restrict the config file's permissions to the user only. The token in this example should be a fine-grained token limited to one repository.
Protect a localhost HTTP server (Go)
Validate Host and Origin, require a bearer token, and bind only to 127.0.0.1. Non-browser clients that have no Origin authenticate with the token.
package main
import (
"crypto/subtle"
"log"
"net"
"net/http"
"os"
)
func protect(allowedHosts, allowedOrigins map[string]bool, token string, next http.Handler) http.Handler {
want := []byte("Bearer " + token)
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// With DNS rebinding, the attacker's domain appears in Host and Origin.
if !allowedHosts[r.Host] {
http.Error(w, "forbidden host", http.StatusForbidden)
return
}
// If Origin is present and not allowed, return 403 (MUST in the spec).
if o := r.Header.Get("Origin"); o != "" && !allowedOrigins[o] {
http.Error(w, "forbidden origin", http.StatusForbidden)
return
}
got := []byte(r.Header.Get("Authorization"))
if subtle.ConstantTimeCompare(got, want) != 1 {
w.Header().Set("WWW-Authenticate", "Bearer")
http.Error(w, "unauthorized", http.StatusUnauthorized)
return
}
next.ServeHTTP(w, r)
})
}
func main() {
token := os.Getenv("MCP_LOCAL_TOKEN") // generate on every launch and hand it to the client
if token == "" {
log.Fatal("MCP_LOCAL_TOKEN is required")
}
mcpHandler := http.NewServeMux() // MCP handling (omitted)
// Bind only to loopback, not to 0.0.0.0.
ln, err := net.Listen("tcp", "127.0.0.1:8931")
if err != nil {
log.Fatal(err)
}
hosts := map[string]bool{"127.0.0.1:8931": true, "localhost:8931": true}
origins := map[string]bool{} // leave empty if browser use is not intended
log.Fatal(http.Serve(ln, protect(hosts, origins, token, mcpHandler)))
}
Write logs to stderr in a stdio server (Go)
package main
import (
"log"
"os"
)
func init() {
// The standard log writes to stderr by default. Make it explicit just in case,
// and leave no code in the server that writes to stdout, such as fmt.Println.
log.SetOutput(os.Stderr)
log.SetFlags(log.LstdFlags | log.Lmsgprefix)
log.SetPrefix("mcp-fs: ")
}
Prevent path traversal (Go 1.24 or later)
os.Root operates confined inside a directory. Escapes via .. or symbolic links pointing outside are rejected at the OS level.
package main
import (
"fmt"
"io"
"os"
)
// readInside reads only files inside the permitted directory root.
func readInside(root *os.Root, name string) ([]byte, error) {
f, err := root.Open(name) // "../../etc/passwd" or a link pointing outside returns an error
if err != nil {
return nil, fmt.Errorf("open %q: %w", name, err)
}
defer f.Close()
return io.ReadAll(io.LimitReader(f, 1<<20)) // also limit the size read
}
func main() {
root, err := os.OpenRoot("/workspace") // the permitted directory passed in by configuration
if err != nil {
panic(err)
}
defer root.Close()
if _, err := readInside(root, "../etc/passwd"); err != nil {
fmt.Fprintln(os.Stderr, err) // rejected
}
}
5. Summary
- A local MCP server is an ordinary process running with the same privileges as the user, and stdio is not a sandbox. It touches environment variables, files, the network, and the whole dependency tree
- There is no way to prove a server's behavior in advance. Treat a third-party local server as untrusted code that has only the privileges you give it, and minimize those privileges
- First, ask whether it needs to run locally. If a remote version exists, use it
- Before installing, check the publisher and package name and pin the version. Pinning with
npxoruvxcovers only the top-level package, so to pin the whole dependency tree, pin the container image by digest. Verify signatures, attestations, and the SBOM - Tool definitions are untrusted input. Read the list, choose a client that re-confirms on changes, and keep the number of servers small
- Isolation is the most effective measure. In a container, pass only the needed directories read-only, block the network if it is not needed, and narrow it with an allowlist if it is
- Pass credentials per server, with narrow scope. Do not export them globally in the shell
- A local HTTP server needs
Originvalidation, binding to 127.0.0.1, and authentication. A stdio server reserves stdout for MCP messages only and confines paths using OS features - Organizations should start with a list of approved servers, an inventory of client configuration, default isolation, and audit logs
Checklist
On your own machine, check the following.
- I know every server in my client configuration and have removed those I do not use
- Servers that need nothing from my machine run remotely rather than locally
- Each server comes from an identifiable publisher and has its version pinned
- Third-party servers run in an isolated environment (container, sandbox, VM) rather than as bare processes
- Each server gets only its own narrowly scoped credentials, passed through per-server configuration (not inherited from the shell, not reused)
- File system access is limited to specific directories, and read-only where possible
- Servers that do not need the network run with egress disabled, and I know the destination list for the rest
- I have read each server's tool descriptions and use a client that re-confirms when tool definitions change
In an organization, check the following.
- There is an allowlist of approved servers and published acceptance criteria
- MCP client configuration on managed machines is inventoried continuously
- The policy for default isolation of local servers is documented
- Audit logs of MCP activity on managed machines are kept
- Egress for a specific server can be blocked and its credentials rotated across the organization
Related Documents
- MCP Security Best Practices - Attacks and Mitigations
- AI Agent-Specific Threats - Prompt Injection and Tool Poisoning
- SBOM and Vulnerability Scanning
- Secure DevOps environments for Zero Trust