Scoring
The design guidelines explain what each dimension is for. This page is the mechanical half: how a score is computed, and every rule that actually runs.
How a score is computed
Section titled “How a score is computed”Each dimension scores 100 × (1 − damage / capacity) — the share of that
dimension’s rules the contract satisfies, weighted by how serious each one is.
Two properties of that formula are deliberate:
- A broken rule counts once, however often it fires. Otherwise a single
chatty rule decides the dimension:
oas3-parameter-descriptionalone fires hundreds of times on a large document. - The denominator is the ruleset, not a fixed 100. Subtracting from a
constant punishes documents for being detailed — a rule like
owasp:api4:2023-string-limitcan only fire on a contract that actually declares strings, so a document defining nothing would outscore a thorough one. Measured as a proportion of the rules in play, describing more of your API can no longer make your score worse by itself.
A dimension with no enabled rules behind it is not reported at all, rather than reported as a flawless 100. “Nothing was wrong” and “nothing was checked” must not look alike.
What a broken rule costs
A rule counts once however often it fires, priced by the severity its ruleset gives it:
| Severity | Cost |
|---|---|
ERROR | 10 |
WARNING | 4 |
INFO | 1 |
HINT | 0.5 |
How dimensions are weighted
| Dimension | Weight | What it measures |
|---|---|---|
| FC | 0.4 | Base layer of spec validity and structural soundness. |
| SEC | 0.3 | Trust, risk posture, and security compliance. |
| DX | 0.2 | Clarity, completeness, and ingestion readiness for developers and tooling. |
| MR | 0.1 | Assesses the API's readiness for mock testing and development. |
Grade bands
- A+≥ 98
- A≥ 94
- A-≥ 90
- B+≥ 85
- B≥ 80
- B-≥ 75
- C+≥ 67
- C≥ 59
- C-≥ 50
- D+≥ 34
- D≥ 17
- D-≥ 0
Where each half lives
Section titled “Where each half lives”Retuning scoring is two different kinds of change, on purpose:
| Concern | Where it lives | Kind of change |
|---|---|---|
| Which rules run, their severity, their dimension | api-scorer/rulesets/evaluation.yaml |
configuration — mountable from a ConfigMap, no rebuild |
| What a breach costs, dimension weights, grade bands | api-scorer/src/domain/scoring.ts |
code |
So a deployment can be retuned without a release, while the shape of the grading curve stays reviewable in one place.
The rules
Section titled “The rules”Everything below is exported from the scorer itself rather than transcribed. The
effective ruleset only exists after composition — Spectral’s oas rules plus the
OWASP ruleset are merged, then the evaluation overlay overrides severities and
stamps each rule with its dimension — so this list is generated by running that
same composition:
cd api-scorer && npm run export:rulesThat rewrites api-portal/src/data/scorer-rules.json, which these tables read.
Re-run it whenever the ruleset or a Spectral dependency changes; the export
carries no timestamp, so an unchanged ruleset produces an empty diff.
OpenAPI
Section titled “OpenAPI”88 rules run against a OPENAPI contract, of which 11 are disabled by default and therefore counts towards neither findings nor coverage.
FC 21 rules
Base layer of spec validity and structural soundness.
| Rule | Severity | What it checks |
|---|---|---|
array-items | ERROR | — |
duplicated-entry-in-enum | WARNING | Enum values must not have duplicate entry. |
no-$ref-siblings | ERROR | Property must not be placed among $ref |
oas2-anyOf | WARNING | anyOf is not available in OpenAPI v2, it was added in OpenAPI v3 |
oas2-discriminator | ERROR | discriminator property must be defined and required |
oas2-oneOf | WARNING | oneOf is not available in OpenAPI v2, it was added in OpenAPI v3 |
oas2-schema | ERROR | Validate structure of OpenAPI v2 specification. |
oas2-unused-definition | WARNING | Potentially unused definition has been detected. |
oas3_1-callbacks-in-webhook | WARNING | — |
oas3_1-servers-in-webhook | WARNING | — |
oas3-callbacks-in-callbacks | WARNING | — |
oas3-schema | ERROR | Validate structure of OpenAPI v3 specification. |
oas3-unused-component | WARNING | — |
operation-operationId-unique | ERROR | Every operation must have unique "operationId". |
operation-parameters | WARNING | Operation parameters are unique and non-repeating. |
operation-tag-defined | WARNING | Operation tags must be defined in global tags. |
path-declarations-must-exist | WARNING | — |
path-keys-no-trailing-slash | WARNING | — |
path-not-include-query | WARNING | Path must not include query string. |
path-params | ERROR | Path parameters must be defined and valid. |
typed-enum | WARNING | Enum values must respect the specified type. |
SEC 36 rules
Trust, risk posture, and security compliance.
| Rule | Severity | What it checks |
|---|---|---|
no-eval-in-markdown | WARNING | Markdown descriptions must not have "eval(". |
no-script-tags-in-markdown | WARNING | Markdown descriptions must not have "<script>" tags. |
oas2-operation-security-defined | WARNING | Operation "security" values must match a scheme defined in the "securityDefinitions" object. |
oas3-operation-security-defined | WARNING | Operation "security" values must match a scheme defined in the "components.securitySchemes" object. |
owasp:api1:2023-no-numeric-ids | ERROR | Use random IDs that cannot be guessed. UUIDs are preferred but any other random string will do. |
owasp:api2:2023-auth-insecure-schemes | ERROR | There are many [HTTP authorization schemes](https://www.iana.org/assignments/http-authschemes/) but some of them are now considered insecure, such as negotiating authentication using specifications like NTLM or OAuth v1. |
owasp:api2:2023-jwt-best-practices | ERROR | JSON Web Tokens RFC7519 is a compact, URL-safe, means of representing claims to be transferred between two parties. JWT can be enclosed in encrypted or signed tokens like JWS and JWE. The [JOSE IANA registry](https://www.iana.org/assignments/jose/jose.xhtml) provides algorithms information. RFC8725 describes common pitfalls in the JWx specifications and in their implementations, such as: - the ability to ignore algorithms, eg. `{"alg": "none"}`; - using insecure algorithms like `RSASSA-PKCS1-v1_5` eg. `{"alg": "RS256"}`. An API using JWT should explicit in the `description` that the implementation conforms to RFC8725. ``` components: securitySchemes: JWTBearer: type: http scheme: bearer bearerFormat: JWT description: |- A bearer token in the format of a JWS and conformato to the specifications included in RFC8725. ``` |
owasp:api2:2023-no-api-keys-in-url | ERROR | API Keys are are passed in headers, cookies or query parameters to access APIs Those keys can be eavesdropped, especially when they are passed in the URL as logging or history tools will keep track of them and potentially expose them. |
owasp:api2:2023-no-credentials-in-url | ERROR | URL parameters MUST NOT contain credentials such as API key, password, or secret. See [RAC_GEN_004](https://docs.italia.it/italia/piano-triennale-ict/lg-modellointeroperabilita-docs/it/bozza/doc/04_Raccomandazioni%20di%20implementazione/04_raccomandazioni-tecniche-generali/01_globali.html?highlight=credenziali#rac-gen-004-non-passare-credenziali-o-dati-riservati-nellurl) |
owasp:api2:2023-no-http-basic | ERROR | Basic authentication credentials transported over network are more susceptible to interception than other forms of authentication, and as they are not encrypted it means passwords and tokens are more easily leaked. |
owasp:api2:2023-read-restricted | WARNING | Read operations (GET, HEAD) should be secured by at least one security scheme. Security schemes are defined in the `securityScheme` section then referenced in the `security` key at the global or operation levels. |
owasp:api2:2023-short-lived-access-tokens | ERROR | Using short-lived access tokens is a good practice, and when using OAuth 2 this is done by using refresh tokens. If a malicious actor is able to get hold of an access token then rotation means that token might not work by the time they try to use it, or it could at least reduce how long they are able to perform malicious requests. |
owasp:api2:2023-write-restricted | ERROR | All write operations (POST, PUT, PATCH, DELETE) must be secured by at least one security scheme. Security schemes are defined in the `securityScheme` section then referenced in the `security` key at the global or operation levels. |
owasp:api3:2023-constrained-additionalProperties | WARNING | By default JSON Schema allows additional properties, which can potentially lead to mass assignment issues, where unspecified fields are passed to the API without validation. Disable them with `additionalProperties: false` or add `maxProperties` |
owasp:api3:2023-constrained-unevaluatedProperties | WARNING | By default JSON Schema allows unevaluated properties, which can potentially lead to mass assignment issues, where unspecified fields are passed to the API without validation. Disable them with `unevaluatedProperties: false` or add `maxProperties` |
owasp:api3:2023-no-additionalProperties | WARNING | By default JSON Schema allows additional properties, which can potentially lead to mass assignment issues, where unspecified fields are passed to the API without validation. Disable them with `additionalProperties: false` or add `maxProperties`. |
owasp:api3:2023-no-unevaluatedProperties | WARNING | By default JSON Schema allows unevaluated properties, which can potentially lead to mass assignment issues, where unspecified fields are passed to the API without validation. Disable them with `unevaluatedProperties: false` or add `maxProperties`. |
owasp:api4:2023-array-limit | ERROR | Array size should be limited to mitigate resource exhaustion attacks. This can be done using `maxItems`. You should ensure that the subschema in `items` is constrained too. |
owasp:api4:2023-integer-format | ERROR | Integers should be limited to mitigate resource exhaustion attacks. Specifying whether int32 or int64 is expected via `format`. |
owasp:api4:2023-integer-limit | ERROR | Integers should be limited to mitigate resource exhaustion attacks. This can be done using `minimum` and `maximum`, which can with e.g.: avoiding negative numbers when positive are expected, or reducing unreasonable iterations like doing something 1000 times when 10 is expected. |
owasp:api4:2023-integer-limit-legacy | ERROR | Integers should be limited to mitigate resource exhaustion attacks. This can be done using `minimum` and `maximum`, which can with e.g.: avoiding negative numbers when positive are expected, or reducing unreasonable iterations like doing something 1000 times when 10 is expected. |
owasp:api4:2023-rate-limit | ERROR | Define proper rate limiting to avoid attackers overloading the API. There are many ways to implement rate-limiting, but most of them involve using HTTP headers, and there are two popular ways to do that: IETF Draft HTTP RateLimit Headers:. https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/ Customer headers like X-Rate-Limit-Limit (Twitter: https://developer.twitter.com/en/docs/twitter-api/rate-limits) or X-RateLimit-Limit (GitHub: https://docs.github.com/en/rest/overview/resources-in-the-rest-api) |
owasp:api4:2023-rate-limit-responses-429 | WARNING | OWASP API Security recommends defining schemas for all responses, even errors. A HTTP 429 response signals the API client is making too many requests, and will supply information about when to retry so that the client can back off calmly without everything breaking. Defining this response is important not just for documentation, but to empower contract testing to make sure the proper JSON structure is being returned instead of leaking implementation details in backtraces. It also ensures your API/framework/gateway actually has rate limiting set up. |
owasp:api4:2023-rate-limit-retry-after | ERROR | Define proper rate limiting to avoid attackers overloading the API. Part of that involves setting a Retry-After header so well meaning consumers are not polling and potentially exacerbating problems. |
owasp:api4:2023-string-limit | ERROR | String size should be limited to mitigate resource exhaustion attacks. This can be done using `maxLength`, `enum` or `const`. |
owasp:api4:2023-string-restricted | WARNING | To avoid unexpected values being sent or leaked, strings should have a `format`, RegEx `pattern`, `enum`, or `const`. |
owasp:api5:2023-admin-security-unique | ERROR | |
owasp:api7:2023-concerning-url-parameter | INFO | Using external resource based on user input for webhooks, file fetching from URLs, custom SSO, URL previews, or redirects, can lead to a wide variety of security issues. Learn more about Server Side Request Forgery here: https://owasp.org/API-Security/editions/2023/en/0xa7-server-side-request-forgery/ |
owasp:api8:2023-define-cors-origin | ERROR | Setting up CORS headers will control which websites can make browser-based HTTP requests to your API, using either the wildcard "*" to allow any origin, or "null" to disable any origin. Alternatively you can use "Access-Control-Allow-Origin: https://example.com" to indicate that only requests originating from the specified domain (https://example.com) are allowed to access its resources. More about CORS here: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS. |
owasp:api8:2023-define-error-responses-401 | WARNING | OWASP API Security recommends defining schemas for all responses, even errors. The 401 describes what happens when a request is unauthorized, so its important to define this not just for documentation, but to empower contract testing to make sure the proper JSON structure is being returned instead of leaking implementation details in backtraces. |
owasp:api8:2023-define-error-responses-500 | WARNING | OWASP API Security recommends defining schemas for all responses, even errors. The 500 describes what happens when a request fails with an internal server error, so its important to define this not just for documentation, but to empower contract testing to make sure the proper JSON structure is being returned instead of leaking implementation details in backtraces. |
owasp:api8:2023-define-error-validation | WARNING | Carefully define schemas for all the API responses, including either 400, 422 or 4XX responses which describe errors caused by invalid requests. |
owasp:api8:2023-no-scheme-http | ERROR | Server interactions must use the http protocol as it's inherently insecure and can lead to PII and other sensitive information being leaked through traffic sniffing or man-in-the-middle attacks. Use the https or wss schemes instead. Learn more about the importance of TLS (over SSL) here: https://cheatsheetseries.owasp.org/cheatsheets/Transport_Layer_Protection_Cheat_Sheet.html |
owasp:api8:2023-no-server-http | ERROR | Server interactions must not use the http:// as it's inherently insecure and can lead to PII and other sensitive information being leaked through traffic sniffing or man-in-the-middle attacks. Use https:// or wss:// protocols instead. Learn more about the importance of TLS (over SSL) here: https://cheatsheetseries.owasp.org/cheatsheets/Transport_Layer_Protection_Cheat_Sheet.html |
owasp:api9:2023-inventory-access | ERROR | Servers are required to use vendor extension x-internal set to true or false to explicitly explain the audience for the API, which will be picked up by most documentation tools. |
owasp:api9:2023-inventory-environment | ERROR | Make it clear which servers are expected to run as which environment to avoid unexpected problems, exposing test data to the public, or letting bad actors bypass security measures to get to production-like environments. |
DX 18 rules
Clarity, completeness, and ingestion readiness for developers and tooling.
| Rule | Severity | What it checks |
|---|---|---|
contact-propertiesoff | WARNING | Contact object must have "name", "url" and "email". |
info-contact | ERROR | Info object must have "contact" object. |
info-description | ERROR | Info "description" must be present and non-empty string. |
info-licenseoff | WARNING | Info object must have "license" object. |
license-urloff | WARNING | License object must include "url". |
oas2-operation-formData-consume-check | WARNING | Operations with "in: formData" parameter must include "application/x-www-form-urlencoded" or "multipart/form-data" in their "consumes" property. |
oas2-parameter-descriptionoff | WARNING | Parameter objects must have "description". |
oas3-parameter-descriptionoff | WARNING | Parameter objects must have "description". |
openapi-tagsoff | WARNING | OpenAPI object must have non-empty "tags" array. |
openapi-tags-alphabeticaloff | WARNING | OpenAPI object must have alphabetical "tags". |
openapi-tags-uniqueness | ERROR | Each tag must have a unique name. |
operation-description | WARNING | Operation "description" must be present and non-empty string. |
operation-operationId | WARNING | Operation must have "operationId". |
operation-operationId-valid-in-url | WARNING | — |
operation-singular-tagoff | WARNING | Operation must not have more than a single tag. |
operation-success-response | WARNING | Operation must have at least one "2xx" or "3xx" response. |
operation-tags | WARNING | Operation must have non-empty "tags" array. |
tag-descriptionoff | WARNING | Tag object must have "description". |
MR 13 rules
Assesses the API's readiness for mock testing and development.
| Rule | Severity | What it checks |
|---|---|---|
oas2-api-host | WARNING | OpenAPI "host" must be present and non-empty string. |
oas2-api-schemes | WARNING | OpenAPI host "schemes" must be present and non-empty array. |
oas2-host-not-exampleoff | WARNING | Host URL must not point at example.com. |
oas2-host-trailing-slash | WARNING | Server URL must not have trailing slash. |
oas2-valid-media-example | ERROR | Examples must be valid against their defined schema. |
oas2-valid-schema-example | ERROR | Examples must be valid against their defined schema. |
oas3-api-servers | WARNING | OpenAPI "servers" must be present and non-empty array. |
oas3-examples-value-or-externalValue | WARNING | Examples must have either "value" or "externalValue" field. |
oas3-server-not-example.comoff | WARNING | Server URL must not point at example.com. |
oas3-server-trailing-slash | WARNING | Server URL must not have trailing slash. |
oas3-server-variables | ERROR | Server variables must be defined and valid and there must be no unused variables. |
oas3-valid-media-example | ERROR | Examples must be valid against their defined schema. |
oas3-valid-schema-example | ERROR | Examples must be valid against their defined schema. |
AsyncAPI
Section titled “AsyncAPI”55 rules run against a ASYNCAPI contract, of which 8 are disabled by default and therefore counts towards neither findings nor coverage.
FC 54 rules
Base layer of spec validity and structural soundness.
| Rule | Severity | What it checks |
|---|---|---|
asyncapi-3-channel-no-empty-parameter | WARNING | Channel address must not have empty parameter substitution pattern. |
asyncapi-3-channel-no-query-nor-fragment | WARNING | Channel address must not include query ("?") or fragment ("#") delimiter. |
asyncapi-3-channel-no-trailing-slash | WARNING | Channel address must not end with slash. |
asyncapi-3-channel-servers | ERROR | Channel servers must be defined in the "servers" object. |
asyncapi-3-document-resolved | ERROR | Checking if the AsyncAPI v3 document has valid structure after resolving references. |
asyncapi-3-document-unresolved | ERROR | Checking if the AsyncAPI v3 document has valid structure before resolving references. |
asyncapi-3-headers-schema-type-object | ERROR | Headers schema type must be "object". |
asyncapi-3-operation-description | WARNING | Operation "description" must be present and non-empty string. |
asyncapi-3-operation-security | ERROR | Operation have to reference a defined security schemes. |
asyncapi-3-payload-unsupported-schemaFormat | INFO | Message schema validation is only supported with default unspecified "schemaFormat". |
asyncapi-3-server-no-empty-variable | WARNING | Server host and pathname must not have empty variable substitution pattern. |
asyncapi-3-server-no-trailing-slash | WARNING | Server host must not end with slash. |
asyncapi-3-server-not-example-comoff | WARNING | Server host must not point at example.com. |
asyncapi-3-tag-descriptionoff | WARNING | Tag object must have "description". |
asyncapi-3-tags | WARNING | AsyncAPI document must have non-empty "tags" array. |
asyncapi-3-tags-alphabeticaloff | WARNING | AsyncAPI object must have alphabetical "tags". |
asyncapi-3-tags-uniqueness | ERROR | Each tag must have a unique name. |
asyncapi-channel-no-empty-parameter | WARNING | Channel path must not have empty parameter substitution pattern. |
asyncapi-channel-no-query-nor-fragment | WARNING | Channel path must not include query ("?") or fragment ("#") delimiter. |
asyncapi-channel-no-trailing-slash | WARNING | Channel path must not end with slash. |
asyncapi-channel-parameters | ERROR | Channel parameters must be defined and there must be no redundant parameters. |
asyncapi-channel-servers | ERROR | Channel servers must be defined in the "servers" object. |
asyncapi-headers-schema-type-object | ERROR | Headers schema type must be "object". |
asyncapi-info-contact | WARNING | Info object must have "contact" object. |
asyncapi-info-contact-properties | WARNING | Contact object must have "name", "url" and "email". |
asyncapi-info-description | WARNING | Info "description" must be present and non-empty string. |
asyncapi-info-license | WARNING | Info object must have "license" object. |
asyncapi-info-license-urloff | WARNING | License object must include "url". |
asyncapi-latest-version | INFO | Checking if the AsyncAPI document is using the latest version. |
asyncapi-message-examples | ERROR | Examples of message object should follow by "payload" and "headers" schemas. |
asyncapi-message-messageId-uniqueness | ERROR | "messageId" must be unique across all the messages. |
asyncapi-operation-description | WARNING | Operation "description" must be present and non-empty string. |
asyncapi-operation-operationId | ERROR | Operation must have "operationId". |
asyncapi-operation-operationId-uniqueness | ERROR | "operationId" must be unique across all the operations. |
asyncapi-operation-security | ERROR | Operation have to reference a defined security schemes. |
asyncapi-payload | ERROR | Payloads must be valid against AsyncAPI Schema object. |
asyncapi-payload-default | ERROR | Default must be valid against its defined schema. |
asyncapi-payload-examples | ERROR | Examples must be valid against their defined schema. |
asyncapi-payload-unsupported-schemaFormat | INFO | Message schema validation is only supported with default unspecified "schemaFormat". |
asyncapi-schema | ERROR | Validate structure of AsyncAPI specification. |
asyncapi-schema-default | ERROR | Default must be valid against its defined schema. |
asyncapi-schema-examples | ERROR | Examples must be valid against their defined schema. |
asyncapi-server-no-empty-variable | WARNING | Server URL must not have empty variable substitution pattern. |
asyncapi-server-no-trailing-slash | WARNING | Server URL must not end with slash. |
asyncapi-server-not-example-comoff | WARNING | Server URL must not point at example.com. |
asyncapi-server-security | ERROR | Server have to reference a defined security schemes. |
asyncapi-server-variables | ERROR | Server variables must be defined and there must be no redundant variables. |
asyncapi-servers | WARNING | AsyncAPI object must have non-empty "servers" object. |
asyncapi-tag-descriptionoff | WARNING | Tag object must have "description". |
asyncapi-tags | WARNING | AsyncAPI object must have non-empty "tags" array. |
asyncapi-tags-alphabeticaloff | WARNING | AsyncAPI object must have alphabetical "tags". |
asyncapi-tags-uniqueness | ERROR | Each tag must have a unique name. |
asyncapi-unused-components-schema | WARNING | Potentially unused components schema has been detected. |
asyncapi-unused-components-server | WARNING | Potentially unused components server has been detected. |
DX 1 rules
Clarity, completeness, and ingestion readiness for developers and tooling.
| Rule | Severity | What it checks |
|---|---|---|
asyncapi-parameter-descriptionoff | WARNING | Parameter objects must have "description". |