Zero-Day Exposure Analysis
Purpose
Identify the user's exposure to zero-day vulnerabilities — CVEs that are actively exploited in the wild before a patch is widely available. Two modes:
- Broad scan — "what zero-days am I exposed to right now?" Enumerate all open exposures whose linked vulnerability carries the
Zero Daytag. - Named zero-day — "am I affected by [name, e.g., Regresshell / Citrix Bleed]?" Resolve the name to CVE IDs via Core, then correlate to the user's environment.
Zero-days often lack a vendor patch at discovery time, so remediation emphasis shifts to compensating controls, detection rules, and scope containment.
When to use
- "Am I exposed to any zero-days?"
- "Show me my open zero-day exposures"
- "Am I affected by [named zero-day]?"
- "List zero-day vulnerabilities in my environment"
- "Zero-day risk report for my account"
Pre-flight
Step 0 — Account preflight (CC-1)
See _shared/account-preflight.md. Required — exposure matches are scoped to the resolved account-id.
Before using this skill, read every file in the references folder, including the shared references/_shared/ docs.
Step 0.5 — Detect composite vs source data model
Exposures and assets are both affected by the composite flag — composite accounts have a separate composite-exposure / composite-asset index with compositeExposure.* / compositeAsset.* field paths and use the exposureQuery / assetQuery tools (source accounts use searchExposureData + aggregateExposureData and searchAssetData). See _shared/composite-vs-source.md. Cache the flag for the turn — picking the wrong model returns empty results with no error.
Suggested tools
Pre-flight
getUserProfile,getEffectiveAccess,getEffectiveAccessWorkspaces
Core intelligence
searchVulnerabilityData— Core index; filter bytags = 'Zero Day'or name/aliassearchThreatActorData— threat actors behind the zero-day. Do NOT passfields: ['threatActor'](actor records are flat — that prefix returns empty silently). Omitfields, or pass top-level keys.
Environment correlation
- Source mode —
searchExposureDatafor the row list andaggregateExposureDatafor bucket counts (two calls, same filter).searchAssetDatafor the asset pivot. - Composite mode —
exposureQuery(combined search + aggregate) andassetQueryfor the asset pivot. UsescompositeExposure.*/compositeAsset.*prefixes. searchComponentData— component-level matches.
Field discovery
getApiFields(entityType=['VULNERABILITY'], searchText='tag')— confirm tag field pathgetTopValues(field='vulnerabilities.tags', entityType='VULNERABILITY')— see what tags exist in this account's Core index
Deep links (CC-2)
createDeepLink(preferred) — mint ashortCodefor every list / aggregation in the response (one call per bucket if you need per-bucket links).getDeepLink(<id>)— URL for a known asset / exposure id.- See _shared/deep-links.md.
Outside
- Web search — resolve named zero-days (e.g., "Regresshell", "Citrix Bleed", "MOVEit") to CVE IDs when Core doesn't match on alias.
Mode A — Broad zero-day scan
User asks "am I exposed to any zero-day?" / "show me my zero-day risk".
Step A.1 — Inventory your environment's zero-day exposures
Source mode — run two calls with the same filter:
// 1) Row list
{
"filters": "exposure.status = 'Open' AND vulnerabilities.tags = 'Zero Day'",
"sort": "exposure.scores.score:desc,exposure.firstIngestedOn:desc",
"limit": 100,
"page": 1
}
// → searchExposureData
// 2) Severity breakdown — same filter
{
"filters": "exposure.status = 'Open' AND vulnerabilities.tags = 'Zero Day'",
"aggs": [{
"name": "bySeverity",
"function": {"type": "TERMS", "field": "exposure.scores.scoreLevel", "size": 10}
}]
}
// → aggregateExposureData
Composite mode — single exposureQuery call with the same filter rewritten as compositeExposure.status = 'Open' AND vulnerabilities.tags = 'Zero Day'.
The vulnerabilities.tags = 'Zero Day' cross-entity join pulls from the vulnerability index (bare path tags = 'Zero Day' in Core).
Step A.2 — Enrich with CVE-level signals
Collect distinct CVE IDs from Step A.1 results. For each (or batched):
searchVulnerabilityData
filter: vulnerabilityId in ('CVE-…','CVE-…')
fields: ['vulnerability']
sort: "riskIndex.index:desc"
Capture: KEV status, exploitation status, risk index, published date, affected products.
Step A.3 — Pivot to affected assets
searchAssetData # source mode
# Composite mode: use `assetQuery` with the same filter, with
# `compositeAsset.assetId` / `compositeAsset.scores.overallScore`.
filter: asset.assetId in (<ids from A.1>)
sort: "asset.scores.overallScore:desc,asset.criticality:desc"
fields: ['asset']
limit: 50
Step A.4 — Emit report
## Zero-Day Exposure Assessment — <account>
**Verdict:** <N open zero-day exposures across M assets; K CVEs; J KEV-tagged>
### Zero-day CVEs in your environment
| CVE | Risk Index | KEV | Exploited | # Exposures | # Assets | Platform link |
|---|---|---|---|---|---|---|
| … | … | ✓/✗ | ✓/✗ | … | … | <url> |
### Open zero-day exposures — by severity
- Critical: <count> — <platform filter url>
- High: <count> — <url>
- Medium: <count> — <url>
- Low: <count> — <url>
### Top affected assets
| Asset | Criticality | Reachability | Workspace | # Zero-day exposures | Platform link |
|---|---|---|---|---|---|
| … | … | … | … | … | <url> |
### Recommended next steps
- Remediation planning: `securin-remediation-guidance` for each CVE — zero-days often have no patch yet, so expect compensating-control emphasis.
- Threat actor context: `securin-threat-correlation` if you want to know who's exploiting these.
- Detailed CVE intel: `securin-cve-enrichment` for any single zero-day.
Mode B — Named zero-day
User asks "am I affected by Regresshell / Citrix Bleed / MOVEit / ?"
Step B.1 — Resolve the name to CVE IDs
Try Core first:
searchVulnerabilityData
filter: tags = 'Zero Day' AND (aliases like '<name>' OR title like '<name>')
fields: ['vulnerability']
limit: 10
If Core matches → use the returned vulnerabilityIds.
If Core doesn't match (very new or informal name):
- Web search for the event + "CVE".
- Present the resolved CVE list to the user: "I found for ''. Confirm before I correlate to your environment."
- Only correlate after confirmation.
Step B.2 — Correlate to environment
Source mode — run search + aggregate with the same filter:
// 1) Itemized list
{
"filters": "exposure.mappedAttributes.vulnerabilityIds in (<cve list>) AND exposure.status = 'Open'",
"sort": "exposure.scores.score:desc,exposure.firstIngestedOn:desc",
"limit": 100,
"page": 1
}
// → searchExposureData
// 2) Workspace breakdown — same filter
{
"filters": "exposure.mappedAttributes.vulnerabilityIds in (<cve list>) AND exposure.status = 'Open'",
"aggs": [
{"name": "byWorkspace", "function": {"type": "TERMS", "field": "asset.workspaces.name", "size": 20}},
{"name": "totalExposures", "function": {"type": "COUNT", "field": "exposure.exposureId"}}
]
}
// → aggregateExposureData
Composite mode: run a single exposureQuery with compositeExposure.* / compositeAsset.* prefixes.
Step B.3 — Enrich and report
Run the affected-assets pivot as in Mode A.3, then emit a named-zero-day report:
## Zero-Day Exposure — <Named Event>
**Mapped CVEs:** <list>
**Verdict:** AFFECTED / NOT AFFECTED / PARTIAL — <N exposures, M assets>
### Matched exposures
| CVE | Severity | Asset | Workspace | SLA | Platform link |
|---|---|---|---|---|---|
### Recommended next steps
- Remediation (likely compensating controls): `securin-remediation-guidance`
- Global intel on the event: `securin-cve-enrichment` for each CVE
FQL patterns
Zero-day tag filter in exposure context
exposure.status = 'Open' AND vulnerabilities.tags = 'Zero Day'
Zero-day filter in Core (bare path — no vulnerabilities. prefix)
tags = 'Zero Day'
Zero-day + KEV (most urgent subset)
exposure.status = 'Open'
AND vulnerabilities.tags = 'Zero Day'
AND vulnerabilities.isCisaKEV = true
Zero-day on exposed-to-internet prod assets (compound)
exposure.status = 'Open'
AND vulnerabilities.tags = 'Zero Day'
AND asset.reachability = 'Exposed' # source-model
AND asset.workspaces.id in (<prod-ws-ids>) # numeric LONGs — unquoted, parens not brackets
Substitute compositeAsset.* in composite-data accounts — see _shared/composite-vs-source.md.
Sorting
Default: exposure.scores.score:desc, exposure.firstIngestedOn:desc — worst first, newest detection as tiebreaker (matches canonical zero-day rule in _shared/sorting-rules.md).
Alternative for "worst externally-facing first":
asset.reachability:desc, exposure.scores.score:desc (if the platform supports ordinal sort on reachability; confirm via getSortFields=true 🧪).
Scope guard (CC-3)
- Single-CVE deep dive with no environment angle →
securin-cve-enrichment. - Broad exposure triage beyond zero-days →
securin-exposure-triage. - Remediation plan for a specific zero-day →
securin-remediation-guidance. - Threat actor attribution for a zero-day →
securin-threat-correlation.
Edge cases
- No zero-day tag in the account — Core may tag these differently (
"0-day","zero day"). CallgetTopValues(field='vulnerabilities.tags')to enumerate actual values and adjust the filter. - User's named event has no CVE yet — tell them; offer to set up a follow-up check once a CVE is published.
- Zero-day with patch now available — still tagged zero-day in Core; route remediation normally.
- False positives — some scanners over-detect; surface the scanner source in the report so the user can filter.
Visual output (CC-4)
When this skill produces aggregated or multi-row data (counts, trends, distributions, comparisons, single-CVE reports), emit a chart/graph/infographic in the Securin brand — multi-series palette (#9C66FF / #7F30FF / #E96001 / #4D268D / #DD639C / …, assigned in order), semantic CHML severity colors (Critical #A60D08 → Info #C5CBD6), Poppins headings on DM Sans body, light theme, and the Securin logo. Use the 10-stop brand purple ramp for heatmaps/sequential scales; gradients are background decoration only — never on chart bars, lines, or slices. Full color system in _shared/brand.md. Offer customization after delivery; never default to a different brand.
References
- Shared: Account Preflight
- Shared: Composite vs Source
- Shared: Deep Links
- Shared: FQL Grammar
- Shared: Sorting Rules
- Shared: Brand & Visual Communication