> For the complete documentation index, see [llms.txt](https://docs.sealsecurity.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.sealsecurity.io/integrations/internal-scanners/checkmarx.md).

# Checkmarx integration

Synchronize Seal's remediation findings into Checkmarx via the Checkmarx API.

<figure><img src="https://2109738374-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FytkIsVkwVdKiLQ2CT6Sw%2Fuploads%2Fgit-blob-3dd537df88cb007efb1006445a3436cd6ba2325c%2Fcheckmarx.png?alt=media" alt="Checkmarx" width="240"><figcaption></figcaption></figure>

The Seal CLI calls the Checkmarx API after every `seal fix` run and updates the corresponding findings in the targeted Checkmarx project. Vulnerabilities Seal has sealed are marked as remediated; vulnerabilities still open stay open. If Seal stops fixing a package it sealed in an earlier run, the CLI moves the findings it marked back to To Verify (see [When Seal no longer fixes a package](#when-seal-no-longer-fixes-a-package)).

## Before you start

* Checkmarx One credentials for the CLI: an API key, or an OAuth client (client ID and secret). The steps to create either are below. Use one or the other, not both.
* The Checkmarx project ID for the project Seal is sealing. In Checkmarx One, open the project and copy the ID from **Project Settings**, or from the project page URL.
* Your Checkmarx tenant URL. For the US hosted offering this is `https://ast.checkmarx.net`; regional tenants use their regional base URL (for example `https://eu.ast.checkmarx.net` or `https://deu.ast.checkmarx.net`). The CLI derives the matching IAM endpoint automatically.

## Creating the API key

A Checkmarx One API key has no permission settings of its own: it inherits the permissions of the user who creates it. The integration needs none (see [Permissions](#permissions)), so create the key from a dedicated service user rather than an admin.

1. Sign in to Checkmarx One as the user the key should belong to.
2. Go to **Settings > Identity and Access Management** (the Settings gear icon sits at the bottom of the left sidebar).

<figure><img src="https://2109738374-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FytkIsVkwVdKiLQ2CT6Sw%2Fuploads%2Fgit-blob-1c44b9fdfec9f815d604738c2e98acf44737e0e5%2Fcheckmarx-settings-menu.png?alt=media" alt="The Checkmarx One Settings menu with Identity and Access Management highlighted" width="220"><figcaption><p>Settings > Identity and Access Management.</p></figcaption></figure>

3. Open the **API Keys** tab and click **Create API Key**.

<figure><img src="https://2109738374-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FytkIsVkwVdKiLQ2CT6Sw%2Fuploads%2Fgit-blob-45d7c4a2bbac54385fcdef8013856043d108c487%2Fcheckmarx-api-keys-page.png?alt=media" alt="The API Keys tab in Checkmarx One Identity and Access Management, with the Create API Key button at the top right"><figcaption><p>The API Keys tab under Identity and Access Management.</p></figcaption></figure>

4. Give the key a recognizable note (for example `seal-integration`) and click **Create**. The expiration period is enforced by your tenant settings.

<figure><img src="https://2109738374-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FytkIsVkwVdKiLQ2CT6Sw%2Fuploads%2Fgit-blob-0da3d77d5aefe4b340063b71635934d138c284c6%2Fcheckmarx-create-api-key.png?alt=media" alt="The Create API Key panel with the Note and Expiration period fields" width="280"><figcaption><p>The Create API Key panel.</p></figcaption></figure>

5. Copy the key from the confirmation dialog immediately and store it in your secret manager. Checkmarx shows the key **only once**; if you close the dialog without copying it, you have to create a new key.

## Permissions

No permissions are needed. Checkmarx does not enforce permissions on the SCA Management of Risk API the CLI uses, or on the custom state list, so any authenticated API key or OAuth client in the tenant can update finding states. Checkmarx states this in its [Management of Risk API documentation](https://docs.checkmarx.com/en/34965-215465-checkmarx-sca--rest--api---management-of-risk.html).

Because of that, keep the credential narrow anyway: a dedicated service user with no roles for the API key, or an OAuth client with its default role mapping.

## Using an OAuth client instead of an API key

If your organization prefers service credentials over user-bound API keys, the CLI can authenticate with an OAuth client (client ID and secret) instead.

Unlike an API key, an OAuth client is not tied to a user.

1. Go to **Settings > Identity and Access Management** and open the **OAuth Clients** tab.
2. Click **Create OAuth Client**, give it a recognizable name (for example `seal-integration`), and create it.
3. Copy the client ID and client secret from the confirmation dialog and store them in your secret manager. Checkmarx shows the secret **only once**.
4. Leave the client's **Role Mapping** as it is. No roles are needed; see [Permissions](#permissions).

You also need your tenant name: the account name shown at **Settings > Identity and Access Management**, also visible in the Checkmarx One login URL after `/auth/realms/`. The API key flow reads it from the key itself, but an OAuth client carries no such information, so it must be configured explicitly.

## Configuration

Set these in your CI environment. With an API key:

```bash
export SEAL_CHECKMARX_URL=<your checkmarx tenant url>
export SEAL_CHECKMARX_TOKEN=<checkmarx api key>
export SEAL_CHECKMARX_PROJECT_ID=<checkmarx project id>
```

With an OAuth client:

```bash
export SEAL_CHECKMARX_URL=<your checkmarx tenant url>
export SEAL_CHECKMARX_CLIENT_ID=<oauth client id>
export SEAL_CHECKMARX_CLIENT_SECRET=<oauth client secret>
export SEAL_CHECKMARX_TENANT=<your checkmarx tenant name>
export SEAL_CHECKMARX_PROJECT_ID=<checkmarx project id>
```

Or in `.seal-config.yml` at the project root:

```yaml
checkmarx:
  url: <your checkmarx tenant url>
  token: <checkmarx api key>
  project-id: <checkmarx project id>
```

```yaml
checkmarx:
  url: <your checkmarx tenant url>
  client-id: <oauth client id>
  client-secret: <oauth client secret>
  tenant: <your checkmarx tenant name>
  project-id: <checkmarx project id>
```

The two credential types are mutually exclusive: set `token` or `client-id`/`client-secret`, not both. If both are set, the CLI skips the integration and logs a warning.

## Marking sealed vulnerabilities with a custom state

By default the CLI marks every sealed vulnerability **Not Exploitable**. If your triage workflow uses Checkmarx One [custom states](https://docs.checkmarx.com/en/34965-378909-custom-states.html), the CLI can apply one of those instead, for example a `Sealed` state that keeps Seal's remediations visibly separate from findings your team dismissed by hand.

Custom states are a Checkmarx One feature for accounts on the new Access Management, and Checkmarx enables it per tenant. If the **Custom States** screen described below is missing from your Settings, ask your Checkmarx contact to enable it.

### Create the custom state in Checkmarx

A tenant admin creates the state once; it is then available to every project in the account.

1. Go to **Settings > Global Settings** and open **Custom States** in the left menu.
2. Click **Add a Custom State**, enter the name (English letters, `-` and `_` only, for example `Sealed`), and click **Add**.

<figure><img src="https://2109738374-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FytkIsVkwVdKiLQ2CT6Sw%2Fuploads%2Fgit-blob-3992a7af8a251fa036b589f6d1acc51fe1b0ee6c%2Fcheckmarx-custom-states-settings.png?alt=media" alt="The Custom States screen under Settings > Global Settings in Checkmarx One, listing a custom state named Sealed"><figcaption><p>Settings > Global Settings > Custom States, with a <code>Sealed</code> state created.</p></figcaption></figure>

The name is what you pass to the CLI, exactly as it appears in this list. Checkmarx identifies custom states by a numeric id in its SCA API; the CLI looks the id up from the name at the start of every run, so you never need to find it yourself.

No extra permissions are needed for custom states either; see [Permissions](#permissions). Creating the state itself is an admin action in the Checkmarx UI.

### Configure the CLI

Add the state name to the configuration from the previous section:

```bash
export SEAL_CHECKMARX_STATE=Sealed
```

Or in `.seal-config.yml`:

```yaml
checkmarx:
  state: Sealed
```

The value can also be one of the predefined states (`ToVerify`, `ProposedNotExploitable`, `NotExploitable`, `Confirmed`, `Urgent`). Leave it unset to keep the default, Not Exploitable.

A custom state has to be resolved before anything is sent, so if the configured name matches no custom state in the tenant, or the state list cannot be read, the CLI sends no updates at all for that run. A predefined state is never looked up and so is unaffected. If Checkmarx rejects an individual update, the remaining updates still go out and only the rejected findings keep their previous state. Every failure is logged as a `callback failed` warning naming the reason, and the `seal fix` run still succeeds.

{% hint style="warning" %}
Not Exploitable is more than a label: Checkmarx removes findings in that state from the aggregated risk counters and shows them struck through. A custom state does not carry that meaning. Sealed vulnerabilities marked with a custom state stay in the Packages tab counters, even after a recalculation, and are not struck through on the Risks tab. If your policies or build gates key off open risk counts, keep the default state.
{% endhint %}

## When Seal no longer fixes a package

Checkmarx keeps a finding's state across scans. So when Seal stops fixing a package it sealed in an earlier run, for example because a Sealing Rule now excludes that package, the findings Seal marked would otherwise keep showing Not Exploitable (or your custom state) while the vulnerable version ships. The CLI undoes its own mark in that case.

After marking the vulnerabilities it sealed, the CLI checks the Management of Risk history of each remaining finding on a package the scan found vulnerable. If the latest state change on the finding is Seal's own (comment `Patched by seal security`), the CLI moves the finding back to **To Verify** with the comment `No longer patched by seal security`.

* A state someone set after Seal's mark is left as is. Only a finding whose latest change came from Seal is moved.
* Findings nobody has triaged are left alone.
* OS packages are skipped, as they are for marking.
* In Local fix mode the CLI only considers packages listed in [`.seal-actions.yml`](/reference/cli/seal-actions-yml.md), so removing a package from that file does not revert its findings. Change their state in Checkmarx by hand.

If the history of a finding cannot be read, the CLI logs a `callback failed` warning naming the finding, leaves its state unchanged, and the `seal fix` run still succeeds.

## Verify

After a `seal fix` run with the integration configured, open the targeted Checkmarx project's SCA results. On the **Risks** tab, every vulnerability sealed by that run is marked **Not Exploitable** and shown with a strikethrough, with a Seal-attributed comment in its Management of Risk history. Vulnerabilities that are not yet sealed, and findings from earlier runs or other projects, keep their previous state. The exception is a finding Seal marked in an earlier run on a package Seal no longer fixes: it moves back to **To Verify** (see [When Seal no longer fixes a package](#when-seal-no-longer-fixes-a-package)).

With a [custom state](#marking-sealed-vulnerabilities-with-a-custom-state) configured, the same rows show that state instead. They are not struck through, and the Packages tab keeps counting them:

<figure><img src="https://2109738374-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FytkIsVkwVdKiLQ2CT6Sw%2Fuploads%2Fgit-blob-220a24b4bfffd979b5ba10f90af8043009bc1127%2Fcheckmarx-risks-sealed-state.png?alt=media" alt="The Checkmarx SCA Risks tab, with the vulnerabilities Seal sealed in the Sealed custom state and the still-open ones in To Verify"><figcaption><p>The Risks tab after a <code>seal fix</code> run with <code>checkmarx.state: Sealed</code>: sealed vulnerabilities carry the custom state, and are not struck through.</p></figcaption></figure>

<figure><img src="https://2109738374-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FytkIsVkwVdKiLQ2CT6Sw%2Fuploads%2Fgit-blob-f0dd84509c735458d4d83cdb0951b6a2ea2188e4%2Fcheckmarx-risks-not-exploitable.png?alt=media" alt="The Checkmarx SCA Risks tab, with the vulnerabilities Seal sealed marked Not Exploitable and struck through, next to still-open To Verify findings"><figcaption><p>The Risks tab after a <code>seal fix</code> run: vulnerabilities sealed by the run are Not Exploitable and struck through; findings the run did not fix stay open.</p></figcaption></figure>

On the **Packages** tab, with the default Not Exploitable state, a package whose vulnerabilities were all sealed drops to zero aggregated risks; a partially sealed package keeps counting the vulnerabilities that are still open. With a custom state the counters do not change.

<figure><img src="https://2109738374-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FytkIsVkwVdKiLQ2CT6Sw%2Fuploads%2Fgit-blob-df7993963488d8bd5b2076ae51aae8bb250d2d85%2Fcheckmarx-packages-after-seal.png?alt=media" alt="The Checkmarx SCA Packages tab, with a fully sealed package showing zero aggregated risks and a partially sealed package still showing one"><figcaption><p>The Packages tab: <code>netmask</code> is fully sealed (0 aggregated risks), <code>axios</code> is partially sealed (open risks still counted).</p></figcaption></figure>

Checkmarx recalculates the risk counters only on the next scan or scan recalculation, so freshly synced findings can show the strikethrough immediately while the summary counters catch up after a recalculation.

## Related

* [How CLI-driven sync works](/integrations/internal-scanners/how-cli-sync-works.md)
