Wiz (cloud security)
The Wiz MCP exposes ~250 tools across 24 security domains behind two gateway tools. You never call a Wiz tool directly: discover finds it, execute runs it. This skill is read-only: investigate, never mutate.
Setup: this skill needs the Wiz MCP server enabled in
.claude/settings.local.jsonand your own Wiz resource IDs in.env(see.env.example):WIZ_REPO_BRANCH_ID(the default-branch REPOSITORY_BRANCH resource for SAST) andWIZ_CONTAINER_REPO_IDS(the container-repository UUIDs for your images). Resolve them once per the "Resolve to IDs" section below, then fill them in — never hardcode real UUIDs in the repo.
The loop
Every query takes the same four steps:
- Route. Call
discover()with no argument to list the domains. Pick the one domain that owns the answer by the type of finding you want, not by nouns in the question (see Routing traps). - Spec. Call
discover(domain)for the exact toolnameand its parameter schema. Read it: params that sound singular are usually arrays (group_by,severity,status,asset_name,container_repository), some are required (e.g.list_issues_groupedneedsgroup_by+type), and thefirst/limitcap differs per tool (often 20). Never guess. - Query. Call
execute(tool_name, parameters)with the exactnamefrom step 2, scoped per the project section below. Ifexecuterejects the name, re-rundiscover(domain)to confirm spelling (some names repeat across domains). - Summarize. A result too large for one response is auto-saved to a
tool-results/*.txtfile instead of returned. Parse it with jq or python (or hand the file to a subagent), never re-read it whole. Report a ranked summary (severity, then affected resource) with the Wiz finding IDs so the user can open each in the portal. Never paste raw JSON back.
Prefer a *_grouped tool with a small first over a raw list: fewer tokens, and it answers "where is the load" directly.
Routing traps
Route by finding type. discover()'s own text carries "Do NOT use for X → Y" notes; these are the most-often mis-routed:
- "AI" in the question does not mean the
ai_securitydomain. Route by what you want about AI: issues toissues, threats tosoc, SAST tocodesec, CVEs tovulnerabilities, sensitive data todspm, compliance tocompliance. Useai_securityonly for the AI resource inventory itself. - Third-party CVE on a cloud resource or image goes to
vulnerabilities; a first-party source-code weakness (SAST) goes tocodesec. "Issues in our images / repo" spans both: image CVEs arevulnerabilities, code flaws arecodesec. Check both when the ask is broad. - A compliance framework score or cross-framework gap goes to
compliance; a single misconfiguration or security rule goes tocspm. - Cloud IAM (principals, entitlements, access keys, MFA) goes to
identity; Wiz portal users and RBAC go tosettings. - EOL, outdated, or unsupported technology goes to
inventory, notcontainer_security.
Resolve to IDs (names lie)
A free-text name filter that returns zero does not mean the resource is absent: asset_name: ["<project name>"] can return nothing even though the project's images exist. Filter by the resource's Wiz UUID instead.
The fastest UUID source is a Wiz portal URL: its hash fragment encodes the exact filter IDs the view uses (resource, containerRepository, ...). Ask the user to paste the portal link for the view they mean, or read the IDs out of one they already sent. Otherwise resolve the UUID with a listing / inventory tool, then filter by it.
The project in Wiz
Typically the project's code and images live under the source host and container registry (e.g. GitHub / ghcr.io), not the cloud account; only the running workloads are on the cloud provider (cloud_platform: ["AWS"] or equivalent, plus your prod account, cluster, and namespace). So a cloud-platform filter hides the image and SAST findings: scope those by the IDs below, not by cloud platform.
- Source repo (SAST →
codesec/list_sast_findings):resource_id: ["${WIZ_REPO_BRANCH_ID}"](the default-branch REPOSITORY_BRANCH resource). Addis_default_branch: true. - Container images (CVEs →
vulnerabilities): filtercontainer_repositoryby the UUIDs in${WIZ_CONTAINER_REPO_IDS}— one per image the project ships.
Default severity to ["CRITICAL", "HIGH"], status to ["OPEN"], and add has_fix: true when the goal is to fix (only fixable findings are actionable). Per finding, layerMetadata.isBaseLayer and artifactType.group (OS_PACKAGE vs CODE_LIBRARY) say whether the fix is a base-image bump or a dependency bump.
execute("list_vulnerability_findings_grouped", {
group_by: ["VULNERABLE_ASSET"], asset_type: ["CONTAINER_IMAGE"],
container_repository: ["<UUID from $WIZ_CONTAINER_REPO_IDS>"],
severity: ["CRITICAL", "HIGH"], status: ["OPEN"], has_fix: true, first: 20 })
Before treating a finding as real
Wiz findings, SAST especially, carry false positives; verify against the code before proposing a fix. Read the flagged line. Example false-positive shapes: a weak hash (SHA-1, MD5) mandated by a protocol or used as a non-security checksum, a timer or callback API flagged as "eval", internal config dirs flagged as path traversal, and template rendering with escaping off that produces plain text rather than HTML.
Read-only guardrail
This skill only investigates. Execute only read tools: names beginning list_, get_, or search_, plus discover.
Refuse any mutating tool: anything that creates, changes, resolves, assigns, deletes, reports, or configures (creating a pentest finding, an automation or remediation rule, a Jira or ServiceNow ticket, changing an issue's status). If the user wants one, say it is out of scope for this skill and point them to the Wiz portal.