> For the complete documentation index, see [llms.txt](https://docs.interlynk.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.interlynk.io/api/security/vulnerabilities-and-vex.md).

# Vulnerabilities and VEX

After an SBOM is processed, the platform attaches known vulnerabilities to its components. You can list them through the API and record a VEX assessment for each one.

You need the environment ID (`projectId`) and version ID (`sbomId`). Get them from [List Products and Versions](/api/inventory/list-resources.md).

## List vulnerabilities

```bash
curl https://api.interlynk.io/lynkapi \
  -H "Authorization: Bearer $INTERLYNK_SECURITY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "query Vulns($projectId: Uuid!, $sbomId: Uuid!, $first: Int, $after: String) { sbom(projectId: $projectId, sbomId: $sbomId) { vulns(sbomId: $sbomId, first: $first, after: $after) { totalCount pageInfo { hasNextPage endCursor } nodes { id vuln { vulnId source sev cvssScore } component { name version } vexStatus { id name } } } } }",
    "variables": {
      "projectId": "1fade833-0603-4139-8ca0-26592264a4c9",
      "sbomId": "4e423fe0-d089-4025-b1e4-8fe9608138d6",
      "first": 25
    }
  }'
```

```json
{
  "data": {
    "sbom": {
      "vulns": {
        "totalCount": 14,
        "pageInfo": { "hasNextPage": false, "endCursor": "MjU" },
        "nodes": [
          {
            "id": "5c11d0e2-0d27-484d-b04f-8df991082652",
            "vuln": {
              "vulnId": "GHSA-72hv-8253-57qq",
              "source": "GITHUB",
              "sev": "medium",
              "cvssScore": 6.9
            },
            "component": { "name": "jackson-core", "version": "2.15.2" },
            "vexStatus": null
          }
        ]
      }
    }
  }
}
```

The `id` on each node is the **component vulnerability ID**. It identifies one vulnerability on one component. You need it to set VEX.

`vulns` is paginated. When `pageInfo.hasNextPage` is `true`, request the next page with `after` set to `endCursor`. See [Conventions](/api/reference/conventions.md).

## Read more about a vulnerability

Two different IDs come back from the list above, and they point at different objects.

* The `id` on each node is the **component vulnerability ID**. It identifies one vulnerability on one component in this version. VEX attaches to it, and it carries the instance-level data: effective CVSS, fix versions, VEX state.
* The `vuln` block is the **global vulnerability record**, shared by every version that has this vulnerability. Its `id` (also exposed on the node as `vulnId`) is what the top-level `vuln` query takes.

So you can read more two ways: expand fields on the node you already have, or look the global record up by its ID.

### Expand the node

Add fields to the same `vulns` query. No second call is needed.

```bash
curl https://api.interlynk.io/lynkapi \
  -H "Authorization: Bearer $INTERLYNK_SECURITY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "query Node($projectId: Uuid!, $sbomId: Uuid!) { sbom(projectId: $projectId, sbomId: $sbomId) { vulns(sbomId: $sbomId, first: 1) { nodes { id effectiveCvssScore effectiveCvssSeverity fixedVersions retracted createdAt vexStatus { name } component { name version purl } vuln { vulnId sev } } } } }",
    "variables": {
      "projectId": "1fade833-0603-4139-8ca0-26592264a4c9",
      "sbomId": "4e423fe0-d089-4025-b1e4-8fe9608138d6"
    }
  }'
```

```json
{
  "data": {
    "sbom": {
      "vulns": {
        "nodes": [
          {
            "id": "1a2735d0-ac84-4dfc-9bd0-ecd78106091a",
            "effectiveCvssScore": 7.5,
            "effectiveCvssSeverity": "high",
            "fixedVersions": ["1.7.0"],
            "retracted": false,
            "createdAt": "2026-01-30T00:08:27Z",
            "vexStatus": null,
            "component": { "name": "jose2go", "version": "v1.5.0", "purl": "pkg:golang/github.com/dvsekhvalnov/jose2go@v1.5.0" },
            "vuln": { "vulnId": "GO-2025-4123", "sev": "high" }
          }
        ]
      }
    }
  }
}
```

Node fields you can read, by group:

| Group              | Fields                                                                                                                             |
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------- |
| Identity           | `id`, `vulnId`, `componentId`, `sbomId`, `createdAt`, `updatedAt`                                                                  |
| Component          | `component { name version purl ... }`                                                                                              |
| Effective CVSS     | `effectiveCvssScore`, `effectiveCvssSeverity`, `effectiveCvssVector`, `hasCustomCvss`, `cvssAdjustedScore`, `cvssAdjustedSeverity` |
| CVSS customization | `cvssTemporalVector`, `cvssEnvironmentalVector`, `cvssTemporalMetrics`, `cvssEnvironmentalMetrics`                                 |
| VEX                | `vexStatus { name }`, `vexJustification`, `cdxResponse`, `note`, `impact`, `detail`, `actionStmt`, `fixedIn`, `vexStatusUpdatedAt` |
| Remediation        | `fixedVersions`, `lastAffectedVersions`, `resolutionDate`, `patchVelocity`                                                         |
| State              | `retracted`, `retractedAt`, `isComplete`, `isPart`, `isFirstDegreePart`                                                            |
| Links              | `externalUrls`, `currentExternalUrls`, `externalIssueTrackerLinks`, `componentVulnCustomFields`, `componentVulnLogs`               |

### Look up the global record

Pass the global vulnerability ID (the node's `vulnId`, or `vuln.id`) to the top-level `vuln` query. Use this for cross-version rollups without going through a single SBOM.

```bash
curl https://api.interlynk.io/lynkapi \
  -H "Authorization: Bearer $INTERLYNK_SECURITY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "query Vuln($id: Uuid!) { vuln(id: $id) { vulnId displayId source sev cvssScore cvssVector desc publishedAt lastModifiedAt componentCount sbomVersionsCount projectGroupsCount vulnInfo { cveId cwes kev epssScore epssPercentile advisories } } }",
    "variables": { "id": "6a89a3c0-c1d0-47ad-b120-7d8390f2d0e8" }
  }'
```

```json
{
  "data": {
    "vuln": {
      "vulnId": "GO-2025-4123",
      "displayId": "CVE-2025-63811",
      "source": "osv",
      "sev": "high",
      "cvssScore": 7.5,
      "cvssVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
      "desc": "Denial-of-Service (DoS) via crafted JWE token high compression ratio in jose2go",
      "publishedAt": "2025-11-18T15:44:15Z",
      "lastModifiedAt": "2026-02-04T04:04:38Z",
      "componentCount": 2,
      "sbomVersionsCount": 2,
      "projectGroupsCount": 1,
      "vulnInfo": { "cveId": "GO-2025-4123", "cwes": [], "kev": false, "epssScore": 0.00029, "epssPercentile": 0.08849, "advisories": ["..."] }
    }
  }
}
```

The `vuln` record fields are `vulnId`, `displayId`, `nvdAliasId`, `source`, `sev`, `cvssScore`, `cvssVector`, `desc`, `publishedAt`, `lastModifiedAt`, `componentCount`, `sbomVersionsCount`, `projectGroupsCount`, and `sbomVersions`. The nested `vulnInfo` adds threat intel: `cveId`, `cwes`, `kev`, `epssScore`, `epssScores`, `epssPercentile`, and `advisories`.

{% hint style="info" %}
One naming gotcha. On a node, `vulnId` is the UUID of the global record, the value the `vuln` query wants. On the `vuln` record itself, `vulnId` is the human advisory string such as `GO-2025-4123`, and `id` is the UUID.
{% endhint %}

## Get the VEX status options

VEX statuses are referenced by ID. Fetch the list of valid statuses first:

```bash
curl https://api.interlynk.io/lynkapi \
  -H "Authorization: Bearer $INTERLYNK_SECURITY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"query": "query { vexStatuses { id name } }"}'
```

```json
{
  "data": {
    "vexStatuses": [
      { "id": "28c61387-c85f-4f9b-b434-4b2d887b8915", "name": "In Triage" },
      { "id": "10cf7c16-b8fb-4731-8622-d874cd2680bc", "name": "Not Affected" },
      { "id": "303b6a94-995f-484d-8ae7-3df89dd4352b", "name": "Affected" },
      { "id": "7fbb2b21-c031-4578-b6e7-9bb78612b6f6", "name": "Fixed" }
    ]
  }
}
```

Fetch these IDs from your own organization. They are stable within an organization, so you can look them up once and reuse them.

Two more lookup queries return the other VEX option lists:

* `vexJustifications { id name }` for justification IDs.
* `cdxResponses { id name }` for response IDs.

## Set a VEX status

`componentVexUpdate` records a VEX assessment on one component vulnerability. Pass the component vulnerability `id` as `componentVulnId`, the version as `currentSbomId`, and the status ID.

```bash
curl https://api.interlynk.io/lynkapi \
  -H "Authorization: Bearer $INTERLYNK_SECURITY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "mutation SetVex($componentVulnId: Uuid!, $currentSbomId: Uuid!, $vexStatusId: Uuid, $note: String) { componentVexUpdate(input: { componentVulnId: $componentVulnId, currentSbomId: $currentSbomId, vexStatusId: $vexStatusId, note: $note }) { componentVuln { id vexStatus { name } note } errors } }",
    "variables": {
      "componentVulnId": "5c11d0e2-0d27-484d-b04f-8df991082652",
      "currentSbomId": "4e423fe0-d089-4025-b1e4-8fe9608138d6",
      "vexStatusId": "10cf7c16-b8fb-4731-8622-d874cd2680bc",
      "note": "Vulnerable code path is not reachable in our usage."
    }
  }'
```

```json
{
  "data": {
    "componentVexUpdate": {
      "componentVuln": {
        "id": "5c11d0e2-0d27-484d-b04f-8df991082652",
        "vexStatus": { "name": "Not Affected" },
        "note": "Vulnerable code path is not reachable in our usage."
      },
      "errors": []
    }
  }
}
```

### componentVexUpdate inputs

| Input                | Type    | Description                                               |
| -------------------- | ------- | --------------------------------------------------------- |
| `componentVulnId`    | Uuid    | The component vulnerability ID. Required.                 |
| `currentSbomId`      | Uuid    | The version the vulnerability belongs to. Required.       |
| `vexStatusId`        | Uuid    | A status ID from `vexStatuses`.                           |
| `vexJustificationId` | Uuid    | A justification ID from `vexJustifications`.              |
| `cdxResponseId`      | Uuid    | A response ID from `cdxResponses`.                        |
| `note`               | String  | Free-text note.                                           |
| `impact`             | String  | Impact statement.                                         |
| `detail`             | String  | Detail statement.                                         |
| `action`             | String  | Action statement.                                         |
| `fixedIn`            | String  | Version the issue is fixed in.                            |
| `propagateVex`       | Boolean | Apply the same VEX to matching components in other SBOMs. |

To update many vulnerabilities at once, use `componentVexBulkUpdate`, which takes a list of `componentVulnIds` and the same VEX fields.

## Errors

Failures return in the `errors` list:

```json
{
  "data": {
    "componentVexUpdate": {
      "componentVuln": null,
      "errors": ["Component vuln not found"]
    }
  }
}
```

See [Errors](/api/reference/errors.md).
