> 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/using-platform/sealing-rules.md).

# Sealing Rules

A **Sealing Rule** instructs the Seal CLI to substitute a sealed version for a vulnerable package when it runs against a Seal Project. Rules describe what to replace, with what, and where the replacement applies.

This page covers the model, the rule types, the precedence between them, and the most common use cases. The two storage locations each have their own page:

* [Remote Sealing Rules](/using-platform/sealing-rules/remote-rules.md) — stored on the Seal Platform, managed in the Seal UI, applied by the Seal CLI in remote mode. This is the default and what most teams use.
* [Local Sealing Rules](/using-platform/sealing-rules/local-rules.md) — stored in a `.seal-actions.yml` file in the customer's repository, applied by the Seal CLI in local mode. Used by the Local deployment method.

## The rule model

Every Sealing Rule has three parts:

| Part                   | What it picks                                                                                                                                                                                          |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Origin target**      | The package the rule replaces. Either a specific package at a specific version (for example, `ejs@2.7.4`), or every package (a blanket "all packages" rule).                                           |
| **Substitute version** | The version Seal substitutes in. Three options: a specific sealed `-sp[N]` (pinned), the safest sealed version (un-pinned), or the origin version itself (used as an exception inside a broader rule). |
| **Scope**              | Where the rule applies. Either one specific Seal Project (project-specific) or every Seal Project in the tenant (tenant-wide).                                                                         |

These choices combine to give four distinct rule types.

## The four rule types

The origin-target axis (specific package vs all packages) crosses with the scope axis (project-specific vs tenant-wide):

|                      | **Project-specific**            | **Tenant-wide**                  |
| -------------------- | ------------------------------- | -------------------------------- |
| **Specific package** | This package, in this project.  | This package, in every project.  |
| **All packages**     | Every package, in this project. | Every package, in every project. |

<figure><img src="/files/GcEqdXFeHXDXqWuhBBFQ" alt="The Sealing rules tab showing examples of the four rule types in a populated table."><figcaption><p>The four rule types as they appear on the Sealing rules tab.</p></figcaption></figure>

The most common rule is project-specific + specific package, written from a vulnerable row on the Protection page. The bottom-right cell — every package in every project — is functionally similar to running the CLI in all mode (the Automatic Remediation deployment method), with the advantage that you can edit it from the UI and write exceptions against it without a code change.

To create a rule that covers **all packages** (either row of the bottom of the table), you have to use the **New rule** button on the [Sealing rules tab](/discovering/protection-page/sealing-rules-tab.md). The per-row create flows (the **Seal** button, the **Seal in all projects** menu item, and the drawer's Seal button) always target a specific package — they start from a vulnerable row, so the package is already chosen.

## Substitute version options

For each rule, the substitute side has three options.

* **A specific `-sp[N]`** (pinned). The CLI substitutes exactly that iteration. New iterations Seal publishes are ignored until you edit the rule. Useful when a regulated build requires reproducibility, when a specific iteration is what passed an audit, or when you want to evaluate a newer iteration before rolling it out tenant-wide. Available only when the origin is a specific package version (you cannot pin "all packages" to one sealed version).
* **The safest sealed version** (un-pinned, the default). The CLI substitutes whichever sealed iteration is currently the safest. When Seal publishes `sp2` after `sp1`, the next CI build pulls `sp2` automatically. Most rules use this.
* **The origin version itself** (exception). The CLI substitutes the same vulnerable version back, which is to say it does not replace the package. This is the way to write an **exception** inside a wider rule. For example, a tenant-wide "all packages" rule that uses the safest version, plus a project-specific package-specific rule for `ejs@2.7.4` that uses the origin version, leaves `ejs@2.7.4` alone in that one project while everything else is sealed.

A rule of "all packages in all projects" can only use the safest version. There is no meaningful pin for a blanket rule, and the exception use case is what the more specific rules are for.

## Precedence between rules

When more than one rule matches a package — for example, a project-specific package-specific rule alongside a tenant-wide "all packages" rule — the platform picks the **most specific** rule and the CLI applies that one. The other rules do not contribute.

Precedence, from highest to lowest:

1. Project-specific, specific package
2. Project-specific, all packages
3. Tenant-wide, specific package
4. Tenant-wide, all packages

The non-obvious part: **project scope dominates package specificity**. A project-specific "all packages" rule wins over a tenant-wide rule for that specific package. The reasoning is that a project's owners are presumed to know better than tenant-wide policy about their own project, even when their rule is broader.

This is what makes the "exception" use case work: a tenant-wide "all packages, safest version" rule combined with a project-specific "this package, origin version" rule leaves that one package alone in that one project while the rest of the tenant gets the safest version.

## Use cases

Most rules are one of:

* **Seal one vulnerable package in one project.** Project-specific, specific package, safest version. The everyday rule, created from a Vulnerable packages tab row.
* **Seal one vulnerable package across the tenant.** Tenant-wide, specific package, safest version. Useful when the same package version appears in many projects and you want consistent treatment without per-project work.
* **Pin a sealed version for compliance.** Project-specific or tenant-wide, specific package, pinned `-sp[N]`. Used in regulated builds; treat the pin as a renewal commitment and revisit on a cadence.
* **Auto-seal everything in one project.** Project-specific, all packages, safest version. Like running the CLI in all mode for that project, but written in the UI so you can revise it without a code change.
* **Auto-seal everything tenant-wide.** Tenant-wide, all packages, safest version. The UI-driven equivalent of the [Automatic Remediation deployment method](/setup-apps-os/choosing-deployment-method.md). Combine with project-specific or package-specific exceptions when needed.
* **Exempt one package from a broader rule.** Pair a wider rule (all packages or tenant-wide) with a more specific rule whose substitute is the origin version. The more specific rule wins and leaves that package alone.

## Remote and Local rules together

Remote and Local rules live in different storage and apply under different Seal CLI modes:

* The Seal CLI in **remote mode** reads remote rules from the Seal Platform and ignores `.seal-actions.yml`.
* The Seal CLI in **local mode** reads `.seal-actions.yml` from the repository and ignores remote rules.

A Seal Project's [deployment method](/setup-apps-os/choosing-deployment-method.md) decides which mode the CLI runs in for that project, so for any given build, only one set of rules is consulted. A project that runs in local mode can still have remote rules on the platform — they just do not affect its builds — and the Protection page lists both so you can see what is configured where.

## Related

* [Remote Sealing Rules](/using-platform/sealing-rules/remote-rules.md): create, edit, and delete remote rules in the Seal UI.
* [Local Sealing Rules](/using-platform/sealing-rules/local-rules.md): the `.seal-actions.yml` schema and how local mode uses it.
* [The Sealing rules tab](/discovering/protection-page/sealing-rules-tab.md): the list view of remote rules.
* [Choosing your deployment method](/setup-apps-os/choosing-deployment-method.md): which rule storage and CLI mode a Seal Project uses.
* [Package states](/discovering/package-states.md): the lifecycle a row moves through as a rule takes effect.
