PROCYON

PRC006 — Personal data returned without authentication

Severityhigh
OWASP API Security Top 10API3:2023 Broken Object Property Level Authorization

What it catches

A response field holding personal data in a GET operation anyone can call: no security requirement of its own or inherited. Marking the operation public (x-procyon-public) does not silence it: it says the operation is meant to be open, which makes exposing personal data through it worse.

Other methods are not checked: a login or sign-up (POST) returns the caller's own data, which is fine.

Personal data, by field name (English and Portuguese, accents ignored): email, phone/telephone/cellphone/mobile number, telefone/celular, CPF, RG, SSN, passport/passaporte, national or tax ID, address/endereço, birth date/data de nascimento, first, last and full name, surname/sobrenome, and their plurals (addresses, celulares). Only text fields (or lists of text) count: emailVerified (a boolean) and emailSettings (an object) are not personal data.

A name does not match when the word right after the personal-data word describes it (emailTemplate, emailVerifiedAt, addressId), or the word right before it makes it something else (supportEmail, the company's; walletAddress, ipAddress, listenAddress).

Why it matters

Whatever an anonymous operation returns, anyone can collect, for every record they can reach, with a script. Exposing personal data this way breaks privacy laws (GDPR, LGPD) and feeds phishing and account takeover.

How to fix it

Require authentication for the operation, and return personal data only to callers allowed to see it. If the operation must stay public, remove the personal fields from its response.

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.

/directory/{id}:
  get:
    x-procyon-ignore:
      - rule: PRC006
        reason: "The directory is public by law"

Examples

Reported:

/profiles/{username}:
  get:
    responses:
      "200":
        content:
          application/json:
            schema:
              properties:
                email:
                  type: string

Not reported: the same operation with a security requirement, or a POST /auth/login returning the caller's own profile.