Security review

ReferenceUpdated 5 min read
View as Markdown
On this page

Every publish runs an automated security review before the registry accepts the version. If any check returns a blocking finding, the publish fails with 422 and the list of findings, and nothing is stored.

The checks

#

Check

What it catches

On failure

1

manifest_schema

package.yaml does not validate

blocking; later checks do not run

2

signature_verify

signature does not match an active certificate of your vendor

blocking

3

meta_coherence

no skills, no inbound events and no peers: nothing to install

blocking

4

entitlement_lint

an unknown entitlement, or network.egress.public where one host would do

blocking

5

blocklist

literal shell(, eval( or exec( in the bundle's source

blocking

6

auth_scheme

a credential auth_type vendors may not use

blocking

7

rate_limits

an outbound method with no rate limit

warning on beta, blocking on internal

8

base_url_lint

a skill routed through an OPVS proxy with an unknown proxy path

blocking

9

network_egress

an upstream host not approved for your vendor

blocking if rejected; warning while pending

10

required_docs

README.md, SKILL.md or CHANGELOG.md missing from the bundle root

blocking

11

aliases_present

no aliases, so agents cannot find the package by the words they use

warning

12

profession_coherence

profession-only rules (see Profession anatomy)

blocking

What runs when. At publish, the registry reviews your manifest and signature. The checks that read files inside the bundle (blocklist, rate_limits on your schemas, required_docs, the profession file checks) run when the bundle itself is reviewed. Run them yourself with the preflight, and treat them as required: they are what a full review checks.

What each check does

manifest_schema validates package.yaml against the rules on The package manifest. Code: manifest.schema, with the failing field path.

signature_verify finds your vendor's active certificate and checks the signature against the bundle hash. Codes: signature.unknown_vendor, signature.revoked, signature.mismatch.

meta_coherence refuses a package with skills: [], inbound_events: [] and peer_dependencies: []. Code: meta.empty_useless. Peers alone are fine (a meta-package).

entitlement_lint checks every entitlement is known: a fixed name, network.egress.provider.<name>, credits.consume.<name> or vendor.<vendor>.<surface>.<verb>. It also refuses network.egress.public when all your outbound URLs share one host. Codes: entitlements.unknown, entitlements.too_broad.

blocklist scans text files in the bundle for shell(, eval( and exec(. exec( is allowed only if the package declares an exec.* entitlement.

auth_scheme allows the credential types pat, api_key, oauth, oauth_pkce and hmac_sha256. Code: credentials.auth_type_unknown.

rate_limits checks that every method with an http line has a rate_limit, on the method or as a package default in provider_config.rate_limit. Code: rate_limit.missing.

base_url_lint applies to vendors whose skills run through an OPVS proxy: the skill's base_url must be one of the proxy paths OPVS gave you. Code: base_url.unknown_proxy_prefix.

network_egress applies when your manifest declares provider_config.upstream. Every host (the upstream and any absolute host in your method URLs) must be approved for your vendor. A new host files an approval request and gives a warning; calls to it are refused until OPVS approves it. A rejected host blocks. Codes: network_egress.host_pending_approval, network_egress.host_rejected.

required_docs requires README.md, SKILL.md and CHANGELOG.md at the bundle root. For the future verified tier, LEARNINGS.md and a non-empty tests/ folder are also expected (warnings today).

aliases_present warns when aliases is empty. Code: discovery.no_aliases.

The score

start            100
each blocking    −25
each warning      −5   (floor 0)

The publish is refused by any blocking finding, whatever the score. A package with only warnings passes with a lower score. The score is stored on the version and shown with the package.

Reading a refusal

{
  "error": "security_review_failed",
  "score": 75,
  "findings": [
    {
      "severity": "blocking",
      "code": "credentials.auth_type_unknown",
      "message": "credential 'ACME_KEY' uses auth_type 'device_code' which is not in the marketplace-approved set",
      "path": "credentials.required[0].auth_type"
    }
  ]
}

Read code first: it names the check. message names the field and value. Fix it, bump the version, and publish again.

Common fixes

Code

Cause

Fix

manifest.schema

unknown key, bad semver, missing trust_domain

follow The package manifest

signature.mismatch

wrong key, or the certificate was rotated

sign with the key of your active certificate

signature.revoked

the certificate was revoked

ask for a new certificate and re-sign

meta.empty_useless

nothing to install

add a skill, or peers for a meta-package

entitlements.unknown

a typo or a made-up name

use a known name or vendor.<you>.<surface>.<verb>

entitlements.too_broad

network.egress.public for one host

use network.egress.provider.<host>

credentials.auth_type_unknown

a reserved credential type

use pat, api_key, oauth, oauth_pkce or hmac_sha256

rate_limit.missing

a method with no rate limit

add rate_limit to the method or provider_config

network_egress.host_pending_approval

a new upstream host

ask vendors@opvs.ai to approve it

discovery.no_aliases

no aliases

add the phrases agents would search for

Running the full review without publishing

The standalone review endpoint (POST /api/v1/security/review on the marketplace) runs every check, including the bundle checks, without storing anything. It accepts only OPVS's platform key today, so ask vendors@opvs.ai to run it on a candidate bundle.

Next

Versions and trust tiers.

Did this answer your question?