# privacy/no-personal-data-in-url

Source: https://apigenie.pl/docs/linter/openapi/rules/privacy-no-personal-data-in-url

This rule reports personal data, such as e-mail addresses, names, dates of birth, phone numbers
and national identification numbers, passed in path or query parameters.

## Rule Details

Personal data in a URL is copied to every access log, proxy, analytics tool and browser history
on its way, mostly outside the retention and access controls that protect the data store. That
works against data minimisation and integrity and confidentiality (GDPR Art. 5(1)(c) and (f)),
data protection by design (Art. 25) and the security of processing (Art. 32), and makes erasure
requests (Art. 17) hard to honour.

The rule looks at every `in: path` and `in: query` parameter, including the parameters of
`components.parameters`, and reports:

- a parameter whose name contains a personal data term, in any naming convention: `email`,
  `phone`, `msisdn`, `first name`, `last name`, `surname`, `date of birth`, `dob`, `ssn`,
  `national id`, `tax id`, `passport`, `iban`, `card number`, `street address`, `ip address`, and
  more;
- special categories of personal data (Art. 9) and criminal records (Art. 10): `health`,
  `diagnosis`, `religion`, `ethnicity`, `sexual orientation`, `biometric`, `genetic`,
  `criminal record`;
- a parameter whose schema has `format: email` or `format: idn-email`;
- an object parameter (`style: form`, `deepObject` or `content`) with such a property.

A term matches whole words of the name, so `name` or `country` alone are not reported, while
`customerEmail` and `LAST_NAME` are. A term followed by `type`, `status`, `verified`, `count` or
`format` describes the data rather than holding it (`email_verified`) and is not reported. Credentials are reported by
`privacy/no-credentials-in-url`.

In a path, identify the resource by an opaque identifier (`/customers/{customerId}`, not
`/customers/{email}`). For a search by personal data, send the criteria in the body of a `POST`
(`POST /customers/search`) or, where the API supports it, of a `QUERY` request.

## Configuration

An object with two optional properties:

- `allow`: parameter and property names that are never reported, compared case-insensitively.
- `terms`: more names to report, in any naming convention (`loyalty card` also finds
  `loyaltyCardNo`).

```yaml
commands:
  lint:
    rules:
      privacy/no-personal-data-in-url:
        - warning
        - allow: [phone]
          terms: [loyalty card]
```

## Examples

**Good**. The search criteria are in the request body.

```yaml
paths:
  /customers/search:
    post:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                email:
                  type: string
                  format: email
```

**Bad**. The e-mail address is part of the URL.

```yaml
paths:
  /customers:
    get:
      parameters:
        - name: email
          in: query
          schema:
            type: string
```

## When Not to Use It

For data that the API publishes on purpose (a public author directory), allow the names or disable
the rule on the parameter with `x-apigenie-lint-disable`.

## Compatibility

This rule is compatible with all OpenAPI 3.x versions.
