C1 Identity & least privilege
Minimal 0.05 / 1.00
Each server acts with one static credential the operator provides: Google Application Default Credentials (or an optional service-account key path) for SecOps and SCC, a VirusTotal key for GTI, and a SOAR app key. Nothing in the code narrows that authority: read and write tools share the credential, there is no read-only identity, and no per-request authorization. The SecOps tools also accept project, customer and region arguments from the caller and build a fresh client for each call, so the model chooses which tenant the credential is applied to. The SOAR key can drive actions across every integration instance the tenant has configured.
C2 Approval gates
Minimal 0.05 / 1.00
The servers expose reads and writes as mostly separate tools, but none carries a risk annotation (no read-only or destructive hints anywhere in the code), none offers a dry run or confirmation step, and there is no server-enforced read-only mode. Destructive tools such as feed deletion, data-table row deletion, watchlist deletion, alert rewriting and SCC mute execute immediately when called. The SOAR server mixes hundreds of action wrappers (including remote command, email and containment actions when enabled) with no signalling of which ones change state. The host is left to decide what to gate with no help from the server.
C3 Tool & action scoping
Minimal 0.38 / 1.00
Tools use typed Python signatures, and a few validate arguments: SCC mute only accepts two values, and every SOAR action checks its scope argument against the list the SOAR server returns. Most free-form arguments are passed straight through, though: raw filters, UDM and YARA-L text, case IDs interpolated into URL paths, and a local file path that GTI opens and uploads to VirusTotal with no path check. SOAR integrations are selected by an operator allowlist and none load by default, which is the main scoping control. Other tools, including all SecOps write tools and the SOAR case tools, are always on.
C4 Code-execution isolation
Minimal 0.05 / 1.00
The server processes themselves contain no local command or code execution path, so nothing runs on the MCP host. The opt-in SOAR wrappers do forward model-supplied commands and scripts to remote endpoints through the tenant's SOAR integrations (SSH run-command, runner commands, CrowdStrike scripts), and these have no sandbox, filtering or approval in this repo. In the default configuration none of those wrappers is registered, because integrations must be named by the operator. Isolation is therefore absent rather than weak, and its blast radius is whichever managed endpoints the operator's SOAR instances reach.
C5 Untrusted input blast radius
Minimal 0.07 / 1.00
These servers read content an attacker can influence: log events, alert and case text, comments, threat-intelligence records and finding descriptions. Outputs come back as plain JSON or text with no provenance flag or untrusted marker, and nothing in the server limits what a hijacked session can then do. Several tool descriptions also carry long next-step guidance telling the model what to do after reading results. A manipulated session can delete feeds, rewrite alerts, ingest forged logs or upload a local file to a public service, all unattended at the server level.
C6 Memory, context & configuration integrity
Minimal 0.20 / 1.00
The servers keep no memory of their own, but they can write model-influenced text into shared systems that later reads feed back into context: SOAR case comments and descriptions, SIEM alert comments, data tables and reference lists. Those stored values are not validated, marked, or isolated per user, so injected text in one session can resurface for other analysts and sessions. Configuration comes from environment variables and the SOAR server loads an environment file with a default dotenv call; the ADK runner reads a .env from its working directory for endpoint and key settings.
C7 Third-party extensions
Minimal 0.30 / 1.00
The servers do not load outside plugins or models. SOAR marketplace modules are in-repo files imported only when the operator names them, and the ADK runner launches the in-repo servers with uv. Nothing pins or hashes dependencies: packages use lower-bound version ranges, no lockfile is committed, and the README launches with uvx from the registry at whatever version is latest. The marketplace modules run in the SOAR server's own process with its key, and launched servers run as the same user.
C8 Secrets & sensitive-data protection
Minimal 0.30 / 1.00
Credentials come from environment variables or a service-account file path; the code does not log them, and there is no telemetry or crash reporting. There is no masking or redaction layer, though, and keys are long-lived: a SOAR app key, a VirusTotal API key and Google credentials. The feed secret tool deliberately returns a newly generated secret into the model's context. Error paths log exception text at debug level without scrubbing.
C9 Audit & traceability
Minimal 0.25 / 1.00
The SecOps server logs some actions at info level to stderr (a line per call for many tools), the SCC server logs searches with their filters, and the SOAR case tools and the roughly 2,000 marketplace wrappers write no log at all (the wrappers use print for errors). The GTI server sets its logger to error level, so its info-level lines never show. No log records arguments, results, caller identity or approvals, and none ships to a store the model cannot touch. Platform-side audit trails in Google Cloud or SOAR exist but are not part of this code.
C10 Limits & kill switch
Minimal 0.33 / 1.00
A few operations have server-side caps, such as a 1000-item page-size ceiling for rule listing and for SCC finding pages, but result counts and time ranges are mostly caller-chosen: SecOps search takes the event count as a parameter, GTI takes a limit argument, and SCC loops until the caller's maximum. There are no rate limits, no concurrency limits, and no cancellation handling in the servers, and VirusTotal file analysis waits for completion with no explicit bound. The ADK runner sets a 60-second stdio timeout on its client side only.