Skip to main content

Reference: Security & Microsoft Defender

StratoLens's own security findings plus Microsoft Defender for Cloud data (plans, assessments, alerts, vulnerabilities) and how they changed between scans. This is the data behind the Defender integration pages. Defender routes need View Defender Assessments; the three security-findings routes need View Resources.

StratoLens Security Findings

GET /api/security-recommendations

Permission: View Resources

Current StratoLens security findings (configuration checks such as RDP open to the internet). Independent of scans. No parameters.

Response: { recommendations[], metadata, totalCount, availableFilters: { categories[], severities[], checkIds[] }, lastUpdatedScanId, lastUpdatedTimestamp }. metadata is { totalFindings, bySeverity: { Critical, High, Medium, Low }, byCategory, privateEndpointBypassCount, lastUpdatedScanId, lastUpdatedTimestamp }; counts are over your scope and null before the first scan. Each finding:

security-recommendations finding fields
FieldMeaning
resourceId (lower-case), originalResourceId, resourceName, resourceType, subscriptionId, subscriptionName, resourceGroupNameResource
checkIdE.g. nsg_rdp_internet
checkTitle, recommendationTitle and what to do
categoryPublicExposure, InsecureConfiguration, Hardening, Identity, Governance
severityCritical, High, Medium, Low
currentValue, expectedValueSetting as found / as expected
instanceKey, instanceLabel?E.g. the NSG rule, for per-rule checks
evidence?nsgRule { ruleName, priority, direction, access, protocol, sources[], ports[], matchedPorts? }; privateEndpointBypass { count, endpointNames[] } (severity raised one level); firewallRules { present, ipRuleCount, virtualNetworkRuleCount, defaultAction? } (PublicExposure downgraded to Low when present); details
firstDetectedScanId, firstDetectedTimestamp, lastUpdatedScanId, lastUpdatedTimestampWhen first detected / last changed

Notes

  • Hidden findings are included, with no hidden marker.
  • "New" in the UI means first detected within 7 days.
  • Unordered.

Example

GET /api/security-recommendations

GET /api/resolved-security-findings

Permission: View Resources

Findings that have gone away. No parameters. Kept about 2 years; removed if the finding comes back.

Response: { resolvedFindings[], totalCount, bySeverity, byCategory }. Each item has the finding fields above (without lastUpdated*) plus:

resolved-security-findings extra fields
FieldMeaning
resolutionTypeconfiguration_remediated or resource_deleted
resolvedAt, resolvedByScanIdWhen and in which scan it resolved

Example

GET /api/resolved-security-findings

GET /api/security-recommendations/attribution

Permission: View Resources

Who most likely caused one finding. Costs a query per call, so don't loop it over every finding.

Parameters

security-recommendations/attribution parameters
NameRequiredNotes
resourceIdyesAny case
checkIdyes

Errors

  • 400Both resourceId and checkId query parameters are required

Response: { actor, actorKind, timestamp, changeId, basis }.

security-recommendations/attribution response fields
FieldMeaning
basischange: a recorded change touched the setting. creation: no such change, so this is who created the resource. none: nothing found; every other field is null
actorDisplay name (may be null)
actorKinduser, automation, system, or null
timestamp, changeIdThe matched change

Notes

  • An unknown check or an out-of-scope resource returns basis: "none", not an error.

Example

GET /api/security-recommendations/attribution?resourceId=%2Fsubscriptions%2F…&checkId=nsg_rdp_internet

Defender Plans and Assessments

GET /api/defender-plans

Permission: View Defender Assessments

Defender plan inventory per subscription in a scan. This route does not accept latest.

Parameters

defender-plans parameters
NameRequired
scanIdyes

Errors

  • 400scanId parameter is required
  • 500Failed to retrieve Defender plan inventory(also for an unknown scan)

Response: { scanId, scanTimestamp, planNames[], subscriptions[] }. Each subscription is { subscriptionId, subscriptionName, enabledBillableCount, plans[] }, sorted by name. Each plan:

defender-plans plan fields
FieldMeaning
planKeyStable <sub>/<plan>
planNameE.g. VirtualMachines, StorageAccounts, CloudPosture
pricingTierFree or Standard
isEnabled, subPlan?Sub-plan e.g. P1/P2
enablementTime?, freeTrialRemainingTime?The latter is an ISO 8601 duration
enforce?, resourcesCoverageStatus?FullyCovered | PartiallyCovered | NotCovered
deprecated?, replacedBy?[]Deprecation
extensions[]{ name, isEnabled, additionalExtensionProperties? }
originalResourceIdAzure-cased ID

Example

GET /api/defender-plans?scanId=…

GET /api/defender-plan-costs

Permission: View Defender Assessments

Defender spend per subscription and plan: this month to date and last month. No parameters. A heavier call: it reads two months of cost data. Only subscriptions with Defender costs appear.

Response: { window: { currentMonth: "YYYY-MM", previousMonth }, subscriptions[] }. Each subscription is { subscriptionId, currentMonthCost, previousMonthCost, currency, mixedCurrency, plans[] }. Each plan:

defender-plan-costs plan fields
FieldMeaning
planNameOr other
currentMonthCost, previousMonthCostAmounts
bySubPlan?Servers P1/P2
trialMeterSeenA $0 cost with a trial meter means trial, not free

Errors

  • 500Failed to retrieve Defender plan costs

Example

GET /api/defender-plan-costs

GET /api/defender-hierarchy-summary

Permission: View Defender Assessmentsaccepts scanId=latest

Defender assessment counts per resource.

Parameters

defender-hierarchy-summary parameters
NameRequired
scanIdyes

Errors

  • 400scanId parameter is required
  • 500Failed to retrieve defender hierarchy summaries

Response: { compactSummaries[], availableFilters: { severities, statuses, assessmentTypes, resourceTypes, categories }, totalCount }. Severity is Low, Medium, High, Critical; status is Healthy, Unhealthy, NotApplicable. Each summary:

defender-hierarchy-summary summary fields
FieldMeaning
entityId, displayName, entityTypeentityId is subscriptionId|resourceGroupName|resourceName|resourceType (one summary per resource and type); displayName is the resource name
subscriptionId, subscriptionName, resourceGroupName?, resourceTypeLocation
totalCountAssessments
severityCounts, statusCountsDictionaries
hiddenCounts{ "true", "false" }
categoryCountsE.g. SoftwareUpdate; missing = Unknown
combinedCountsKey severity|status|hidden|category

Example

GET /api/defender-hierarchy-summary?scanId=latest

GET /api/defender-resource-details

Permission: View Defender Assessmentsaccepts scanId=latest

All Defender assessments for one subscription or resource. An out-of-scope subscription returns an empty result.

Parameters

defender-resource-details parameters
NameRequiredNotes
scanId, subscriptionIdyes
entityTypenosubscription or resource; default resource
resourceGroupName, resourceNamefor resource

Errors

  • 400entityType must be one of subscription, resource
  • 400subscriptionId and scanId parameters are required
  • 400resourceName and resourceGroupName parameters are required for resource queries
  • 500Failed to retrieve defender resource details

Response: { assessments[], totalCount, cveDetails? }, newest first. cveDetails maps CVE ID to a catalog entry of the shape shown under vulnerability routes. Each assessment:

Defender assessment fields
FieldMeaning
assessmentIdStable identity
displayName, description, remediationDescription?Text
status, severity, riskLevel?State
recommendationCategory?, assessmentType?Classification
resourceId, originalResourceId, resourceName, resourceGroupName, resourceType, subscriptionId, subscriptionName, entityTypeResource
portalLink?Azure portal link
softwareVendor?, softwareName?, packageType? (OS | DevPackage), detectedSoftwareVersions?, fixedVersion?, fixAvailable?, maxCvssScore?Vulnerability rows
cveIds?Up to 100, ranked
totalCveCount?The true count; use this, not cveIds.length
targetType?, imageRegistryHost?, imageRepository?, imageDigest?, imageTags?Container images
firstEvaluationDate?, statusChangeDate?, firstScanTimestamp, lastScanTimestampTimes
isHidden?, notes?User annotations, with the audit fields lastNotesUpdatedBy?, lastNotesUpdatedAt?, lastHiddenUpdatedBy?, lastHiddenUpdatedAt?
Also presentassessmentName, timestamp, initiatedBy, riskFactors?, isContextualRisk?, resourceProvider?, source?, policyDefinitionId?, implementationEffort?, userImpact?, threats?, tactics?, techniques?, securityCategories?, cloudProviders?, preview?, statusCause?, statusDescription?, language?, imagePushedAt?. The riskFactors, threats, tactics, techniques, securityCategories and cloudProviders fields are string arrays

Example

GET /api/defender-resource-details?scanId=latest&subscriptionId=<guid>&resourceGroupName=rg-web&resourceName=vm-web-01

Defender Alerts

GET /api/defender-alerts-hierarchy-summary

Permission: View Defender Assessmentsaccepts scanId=latest

Security alert counts per entity. Includes resolved and dismissed alerts.

Parameters

defender-alerts-hierarchy-summary parameters
NameRequired
scanIdyes

Errors

  • 400scanId parameter is required
  • 500Failed to retrieve defender alert hierarchy summaries

Response: { compactSummaries[], availableFilters: { severities, statuses, intents }, totalCount }. Each summary:

defender-alerts-hierarchy-summary summary fields
FieldMeaning
entityId, displayName, entityTypeentityId is subscriptionId|resourceGroup|resourceName|resourceType
subscriptionId, subscriptionName, resourceGroupName?, resourceTypeLocation
totalCountAlerts
severityCountsHigh, Medium, Low, Informational
statusCountsActive, InProgress, Resolved, Dismissed
hiddenCountsHidden vs. visible
intentCountsMITRE intents; a multi-intent alert counts once per intent
combinedCountsKey severity|status|hidden|intent. The intent part can itself be a comma list, so split it on ,

Example

GET /api/defender-alerts-hierarchy-summary?scanId=latest

GET /api/defender-alerts-resource-details

Permission: View Defender Assessmentsaccepts scanId=latest

Alerts for one entity, at that exact level only. A resource-group query does not include its resources' alerts. An out-of-scope subscription returns an empty 200 ({ alerts: [], totalCount: 0 }).

Parameters

defender-alerts-resource-details parameters
NameRequiredNotes
scanId, subscriptionIdyes
entityTypenosubscription, resourceGroup, resource; default resource
resourceGroupName, resourceNameper entityType

Errors

  • 400entityType must be one of subscription, resourceGroup, resource
  • 400subscriptionId and scanId parameters are required
  • 400resourceName and resourceGroupName parameters are required for resource queries
  • 400resourceGroupName parameter is required for resource group queries
  • 500Failed to retrieve defender alert resource details

Response: { alerts[], totalCount }, newest first. Each alert:

Defender alert fields
FieldMeaning
systemAlertIdAlert instance ID
alertTypeE.g. VM_EICAR
alertDisplayName, descriptionText
severity, statusAs in the summary
compromisedEntityMost-affected resource
intent, techniques[], subTechniques[]MITRE
startTimeUtc, endTimeUtc, timeGeneratedUtcTimes
remediationSteps[]Steps
alertUriAzure portal link
isIncident, correlationKeyGrouping
entities[], resourceIdentifiers[]Raw Azure arrays
vendorName, productName, productComponentName?Product info
Resource identity fieldsAs on assessments
isHidden?, notes?User annotations

Example

GET /api/defender-alerts-resource-details?scanId=latest&entityType=resourceGroup&subscriptionId=<guid>&resourceGroupName=rg-web

Vulnerabilities

Shared terms for the vulnerability routes

  • cveId: CVE-YYYY-NNNN (4+ digits, any case).
  • softwareKey: identifies a vulnerable package. Copy it from software[].softwareKey in defender-vulnerability-summary or getDefenderVulnerabilityDiff, then URL-encode it (| becomes %7C). Do not build it yourself.
  • resourceKey: identifies an assessed resource; container-image findings roll up under their registry. Copy it from resources[].resourceKey and URL-encode it.
  • resourceTypes: CSV of exact ARM types, e.g. microsoft.compute/virtualmachines. Valid values are in availableResourceTypes.
  • showHidden: on defender-vulnerability-summary, defender-vulnerability-resources and defender-vulnerability-findings only the string true includes hidden items (default excludes). The two vulnerability diff routes have no showHidden and always include hidden findings.
  • CVE catalog entries have the shape { cveId, severity, cvssScore?, cvssVersion?, epssScore?, epssPercentile?, isInExploitKit, isPubliclyDisclosed, exploitVerified, publishedDate?, lastModifiedDate? }.

Errors

  • 400Provide only one of cveId or softwareKey
  • 400cveId must be a CVE identifier (CVE-YYYY-NNNN)
  • 400softwareKey is malformed
  • 400Exactly one of cveId or softwareKey is required

These four are the selector errors referenced by the routes below.

GET /api/defender-vulnerability-summary

Permission: View Defender Assessments

Every CVE and vulnerable software package in a scan, with counts. Sorted by resourceCount, highest first.

Parameters

defender-vulnerability-summary parameters
NameRequired
scanIdyes
showHiddenno
resourceTypesno

Errors

  • 400scanId parameter is required
  • 500Failed to retrieve vulnerability summary

Response: { scanId, scanTimestamp, cves[], software[], totals, catalogState, availableResourceTypes[], planCoverage? }.

defender-vulnerability-summary response fields
FieldMeaning
cves[]{ cveId, findingCount, resourceCount, subscriptionCount, fixAvailableCount, catalog? }
software[]{ softwareKey, softwareVendor?, softwareName, packageType?, findingCount, resourceCount, subscriptionCount, fixAvailableCount, cveCount, exploitedCveCount, maxCvssScore?, maxSeverity }
totals{ findingCount, resourceCount, cveCount, softwareCount }
catalogStatesynced or never-synced. When never-synced, CVE rows have no catalog
planCoverage?Present only when there are no findings and no filter: { inventoryPresent, coveredSubscriptionCount, subscriptionCount } tells you whether any vulnerability-assessment plan is on

Notes

  • Container images are counted per image in resourceCount.
  • fixAvailableCount means the package has a fix, not necessarily for that CVE.

Example

GET /api/defender-vulnerability-summary?scanId=…&resourceTypes=microsoft.compute/virtualmachines

GET /api/defender-vulnerability-resources

Permission: View Defender Assessments

Which resources one CVE or package affects, most severe first.

Parameters

defender-vulnerability-resources parameters
NameRequired
scanIdyes
cveId or softwareKeyyes (exactly one)
showHiddenno
resourceTypesno

Errors

  • 400scanId and selector errors
  • 500Failed to retrieve affected resources

Response: { resources[], findingCount }. Each resource: { resourceKey, resourceName, resourceType, subscriptionId, subscriptionName?, resourceGroupName?, findingCount, imageCount, maxSeverity }.

Example

GET /api/defender-vulnerability-resources?scanId=…&cveId=CVE-2024-6387

GET /api/defender-vulnerability-findings

Permission: View Defender Assessments

One page of a CVE's or package's findings on one resource.

Parameters

defender-vulnerability-findings parameters
NameRequiredNotes
scanIdyes
cveId or softwareKeyyes (exactly one)
resourceKeyyes
showHidden, resourceTypesno
pageno≥ 1, default 1
pageSizeno1-100, default 20

Errors

  • 400scanId parameter is required
  • 400Selector errors (the four listed under the shared terms above); checked before resourceKey, page and pageSize
  • 400resourceKey parameter is required
  • 400page must be a positive integer
  • 400pageSize must be between 1 and 100
  • 500Failed to retrieve vulnerability findings

Response: { assessments[], totalCount, totalPages, currentPage, cveDetails }. Assessments are full objects, as in defender-resource-details.

Example

GET /api/defender-vulnerability-findings?scanId=…&softwareKey=red_hat%7Cpython3-libs_for_linux%7COS&resourceKey=%2Fsubscriptions%2F…&page=1&pageSize=50

GET /api/defender-cve-detail

Permission: View Defender Assessments

The full catalog entry for one CVE. The catalog is shared across the installation and is not scope-filtered. Only CVEs seen in a scan are present.

Parameters

defender-cve-detail parameters
NameRequiredNotes
cveIdyesAny case

Errors

  • 400cveId parameter is required and must be a CVE identifier (CVE-YYYY-NNNN)
  • 404CVE not in catalog
  • 500Failed to retrieve CVE detail

Response

defender-cve-detail response fields
FieldMeaning
cveId, severityIdentity and severity
cvssScore?, cvssVersion?, cvssVectorString?CVSS
epssScore?, epssPercentile?EPSS
isInExploitKit, isPubliclyDisclosed, exploitVerifiedExploit flags
exploitTypes?, exploitUris?Up to 5 URIs
summary?, impact?, remediation?Text
weaknesses?CWE IDs
references?Up to 10 of { source, title, url }
publishedDate?, lastModifiedDate?, lastSyncedAtDates

Example

GET /api/defender-cve-detail?cveId=CVE-2024-6387

Scan-to-Scan Diffs

All of these take a scan pair. The summary routes return counts only; the details routes return the items.

GET /api/getDefenderAssessmentDiff

Permission: View Defender Assessments

Assessment change counts between two scans, by hierarchy. Any content change counts as modified, including a status change such as Unhealthy to Healthy.

Parameters

getDefenderAssessmentDiff parameters
NameRequired
baseScanId, compareScanIdyes

Errors

  • 400Scan-pair errors
  • 500An error occurred while processing the defender assessment comparison.

Response: { summary, assessments, hierarchySummary[], availableFilters: { categories[] } }.

getDefenderAssessmentDiff response fields
FieldMeaning
summary{ baseScanId, compareScanId, baseScanTime?, compareScanTime?, added, deleted, modified }
assessmentsAlways empty; use the details route for the items
hierarchySummary[]{ subscriptionId, subscriptionName, resourceGroupName?, resourceName?, entityType, addedCount, modifiedCount, deletedCount, totalChanges }. Don't sum across levels

Example

GET /api/getDefenderAssessmentDiff?baseScanId=<older>&compareScanId=<newer>

GET /api/getDefenderAssessmentDiffDetails

Permission: View Defender Assessments

Paged changed assessments for one entity. Order: added, then modified, then deleted. An out-of-scope subscription returns an empty 200 page. That scope check runs before the scan pair is resolved, so an out-of-scope subscription with an unknown or reversed pair also gets the empty 200, not a 404 or 400.

Parameters

getDefenderAssessmentDiffDetails parameters
NameRequiredNotes
baseScanId, compareScanIdyes
subscriptionIdyesExact; copy from hierarchySummary
resourceGroupName, resourceNamenoA resource group includes all its assessments
resourceKeynoExact resource, including registry image findings
cveId / softwareKeyno, at most oneCompares only vulnerable findings with that CVE or package. A finding that became healthy shows as deleted
changeTypenoCSV of added, modified, deleted
severitynoCSV
categoriesnoCSV; Unknown matches no category
showHiddennoHere only false drops hidden items; anything else keeps them
pagenoDefault 1
pageSizeno1-100, default 25

Errors

  • 400<name> must list at most 200 values
  • 400Missing-pair message, selector errors, scan-pair 404/400
  • 400Please provide 'subscriptionId' query parameter.
  • 400Invalid 'changeType' parameter. Must be 'added', 'modified', or 'deleted'.
  • 400page and pageSize errors as in defender-vulnerability-findings
  • 500An error occurred while processing the defender assessment diff details.

Response: { assessments[], totalCount, totalPages, currentPage }. Each assessment is a full object plus changeStatus and changes[] of { property, before, after }. For added and deleted items this holds one entry with the whole object.

Example

GET /api/getDefenderAssessmentDiffDetails?baseScanId=…&compareScanId=…&subscriptionId=<guid>&changeType=added,modified&severity=Critical,High&showHidden=false&pageSize=50

GET /api/getDefenderAlertDiff

Permission: View Defender Assessments

Alert change counts between two scans. A status change (e.g. Active to Resolved) is modified.

Parameters

getDefenderAlertDiff parameters
NameRequired
baseScanId, compareScanIdyes

Errors

  • 400Scan-pair errors
  • 500An error occurred while processing the defender alert comparison.

Response: { summary, alerts: [] (always empty), hierarchySummary[] }, with the same shapes as the assessment diff.

Example

GET /api/getDefenderAlertDiff?baseScanId=…&compareScanId=…

GET /api/getDefenderAlertDiffDetails

Permission: View Defender Assessments

Paged changed alerts for one entity, newest first. An out-of-scope subscription returns an empty 200 ({ alerts: [], totalCount: 0, totalPages: 1, currentPage: 1 }), even when the scan pair is unknown or reversed, because the scope check runs first.

Parameters

getDefenderAlertDiffDetails parameters
NameRequiredNotes
baseScanId, compareScanId, subscriptionIdyes
resourceGroupName, resourceNameno
entityTypenosubscription, resourceGroup, resource
changeTypenoOne value only
severitynoCSV
page, pageSizenoDefault 15, max 100. Out-of-range values are adjusted silently, never a 400

Errors

  • 400Missing-pair message, scan-pair 404/400
  • 400Please provide 'subscriptionId' query parameter.
  • 400Invalid 'changeType' parameter. Must be 'added', 'modified', or 'deleted'.
  • 400Invalid 'entityType' parameter. Must be 'subscription', 'resourceGroup', or 'resource'.
  • 500An error occurred while processing the defender alert diff details.

Response: { alerts[], totalCount, totalPages, currentPage }. Each alert is a full alert plus changeStatus. Modified items also carry changes[] covering status, severity, intent, alertDisplayName, description, compromisedEntity, techniques, subTechniques, remediationSteps, startTimeUtc, endTimeUtc, entities, isIncident, correlationKey.

Example

GET /api/getDefenderAlertDiffDetails?baseScanId=…&compareScanId=…&subscriptionId=<guid>&changeType=added&severity=High,Medium

GET /api/getDefenderPlanDiff

Permission: View Defender Assessments

Defender plan changes between two scans. Free-trial countdown and coverage-status changes do not count as modifications.

Parameters

getDefenderPlanDiff parameters
NameRequired
baseScanId, compareScanIdyes

Errors

  • 400Scan-pair errors
  • 500An error occurred while processing the Defender plan comparison.

Response: { summary: { …, added, modified, deleted }, subscriptions[] }. Each subscription is { subscriptionId, subscriptionName, addedCount, modifiedCount, deletedCount, changes[] }. Each change is a plan (fields as in defender-plans) plus changeStatus and, when modified, changes[] over pricingTier, subPlan, enablementTime, enforce, deprecated, replacedBy and extensions.<Name>.*.

Example

GET /api/getDefenderPlanDiff?baseScanId=…&compareScanId=…

GET /api/getDefenderVulnerabilityDiff

Permission: View Defender Assessments

Which CVEs and packages appeared, disappeared or changed reach between two scans. Hidden items are included.

Parameters

getDefenderVulnerabilityDiff parameters
NameRequired
baseScanId, compareScanIdyes
resourceTypesno

Errors

  • 400Scan-pair errors
  • 500An error occurred while processing the vulnerability comparison.

Response: { summary: { …, totals: { cves: { added, modified, deleted }, software: { … } } }, cves[], software[], catalogState, availableResourceTypes[] }. Each row (CVE or software):

getDefenderVulnerabilityDiff row fields
FieldMeaning
changeStatusDecided by the set of affected resources: none before = added, none after = deleted, different = modified
olderResourceCount, newerResourceCountReach before and after
addedResourceCount, removedResourceCountResources gained and lost
subscriptionCountSubscriptions affected
addedFindingCount, modifiedFindingCount, deletedFindingCountFinding-level counts
CVE rowsAdd cveId and catalog?
Software rowsAdd softwareKey, softwareVendor?, softwareName, packageType?, cveCount, exploitedCveCount, maxCvssScore?, maxSeverity

Notes

  • A CVE affecting the same resources in both scans is omitted, even if versions changed.

Example

GET /api/getDefenderVulnerabilityDiff?baseScanId=…&compareScanId=…

GET /api/defender-vulnerability-resource-diff

Permission: View Defender Assessments

For one CVE or package, which resources' findings changed between two scans.

Parameters

defender-vulnerability-resource-diff parameters
NameRequired
baseScanId, compareScanIdyes
cveId or softwareKeyyes (exactly one)
resourceTypesno

Errors

  • 400Selector and scan-pair errors
  • 500An error occurred while processing the vulnerability resource comparison.

Response: { resources[] }. Each resource: { resourceKey, resourceName, resourceType, subscriptionId, subscriptionName?, resourceGroupName?, addedCount, modifiedCount, deletedCount }.

Notes

  • To list the changed findings, pass resourceKey with the same selector to getDefenderAssessmentDiffDetails.

Example

GET /api/defender-vulnerability-resource-diff?baseScanId=…&compareScanId=…&cveId=CVE-2024-6387

Was this page helpful?