PROCYON

PRC103 — Malformed request made the server fail

Severitymedium
OWASP API Security Top 10API8:2023 Security Misconfiguration
Found byprocyon test (runtime)

What it catches

For every operation that is not public and whose request body has an example in the spec, procyon test sends, as test account A, the example itself and then a few bodies the schema forbids, built from it in fixed ways (never randomly), fields in name order:

  • the first required field with known types (else the first field with known types) set to a value of none of them: "title": 42;
  • the first required field the example has, left out;
  • the first string field with an enum, set to a value outside it;
  • the first string field with a maxLength, one character too long; or, when no string field has one, the first string field at 100 000 characters.

If a mutation gets a 5xx, or no answer within the timeout (a regular expression that backtracks on a long string takes the server down for everyone), it is a finding. If the unchanged example already gets a 5xx, nothing is reported for the operation: a note says so, as it does when the example gets any other non-2xx (a 404 would refuse every mutation for another reason). Malformed requests run after B's checks on every write and before the deletes, so an accepted one never hides what B can do to A's object. After a request that got no answer, nothing more is sent: the operations and deletes left are listed under Notes, since the server may stay busy for minutes.

Why it matters

A 5xx means the input reached code that did not expect it: an unchecked type assertion, a database constraint, a parser. Those paths leak stack traces and internal details, and the ones that crash are where denial of service and injection start.

How to fix it

Validate the request body against the schema before using it, and answer 400 with what is wrong. Most frameworks can validate against the OpenAPI schema directly.

How to ignore it

If the finding is fine on purpose, write an x-procyon-ignore on the operation, with the reason. The finding is still reported, under Ignored, and no longer fails the run. See ignoring a finding.

/imports:
  post:
    x-procyon-ignore:
      - rule: PRC103
        reason: "Legacy importer, replaced in Q3; errors are not exposed"

Known limits

  • A field whose schema gives no type, or composes it (allOf, oneOf, anyOf, not), never gets a wrong type: any value may be valid.
  • Bodies described only through allOf/oneOf at the top level, with no properties, get no mutations.
  • Public operations (a login) are not sent malformed bodies, and neither are operations without a JSON object example.

Examples

Reported: the example is {"title": "Shopping list"}, and

POST /notes {"title": 42}     (as A)
500 {"error":"internal error"}

Not reported: the same request answered 400.