> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pharussecurity.com/llms.txt
> Use this file to discover all available pages before exploring further.

# security.txt

> The RFC 9116 security.txt Pharus generates for you: its fields, how Expires stays fresh, and how to serve it from your own domain.

<Info>
  **Plans:** Every plan, and Free. **Who:** public; owners and admins change its fields under **Settings → Disclosure**.
</Info>

security.txt (RFC 9116) is a small text file that tells researchers and their tools how to report a vulnerability to you. Pharus generates yours from your disclosure settings and hosts it next to your [disclosure page](/disclosure/disclosure-page). To be found, it has to be served from your own domain as well, at `https://<your-domain>/.well-known/security.txt`.

## Endpoint

```http theme={null}
GET https://app.pharussecurity.com/disclose/<your-slug>/security.txt
```

| Response | Details |
| - | - |
| `200` | The file, with `Content-Type: text/plain; charset=utf-8`, `Cache-Control: public, max-age=300` and `Access-Control-Allow-Origin: *`. |
| `404` | Unknown slug, or a workspace an owner has closed. The body is `Not found`. |

Changes you save in **Settings → Disclosure** can take up to five minutes to show, because of the cache. The same text is on the **security.txt** card in **Settings → Disclosure**.

## The file

```text theme={null}
Contact: mailto:security@nordlys.no
Contact: https://app.pharussecurity.com/disclose/<your-slug>
Expires: 2027-09-14T08:12:33.000Z
Encryption: https://nordlys.no/pgp-key.txt
Preferred-Languages: no, en
Canonical: https://nordlys.no/.well-known/security.txt
Policy: https://app.pharussecurity.com/disclose/<your-slug>/policy
CSAF: https://app.pharussecurity.com/csaf/<your-slug>/provider-metadata.json
```

Pharus writes the fields in this order, one per line:

| Field | Value | When |
| - | - | - |
| `Contact` | `mailto:` and your **Public contact email** | When the email is set. It comes first. |
| `Contact` | Your report form, `https://app.pharussecurity.com/disclose/<your-slug>` | Always. |
| `Expires` | A date and time in UTC. See [Expires](#how-expires-stays-fresh). | Always. |
| `Encryption` | Your **OpenPGP key URL** | When set. |
| `Preferred-Languages` | `no, en`: Norwegian and English | Always. |
| `Canonical` | Your **Canonical URL**, or else the hosted file's own address | Always. |
| `Policy` | Your policy page, `https://app.pharussecurity.com/disclose/<your-slug>/policy` | Always. |
| `CSAF` | Your [CSAF provider metadata](/api-reference/csaf-feed) | Once you have published a TLP:WHITE advisory. |

The file has no `Acknowledgments` or `Hiring` field, and it isn't signed with OpenPGP. The policy and form links have no language parameter, so they open in your company's **Default language**.

## How Expires stays fresh

RFC 9116 recommends an `Expires` less than a year ahead. Under **Settings → Disclosure → Expires** you choose how:

* **Leave it empty.** The hosted file gets a fresh date every time it is served, always 11 months ahead, so it never goes stale.
* **Pick a date.** It must be in the future and less than a year ahead. The file then expires at midnight Oslo time at the start of that day, written in UTC, and Pharus doesn't move it. Change it before it passes.

A copy on your own server keeps the date it had when you copied it, whichever you choose.

## Serve it from your own domain

RFC 9116 asks for the file at `/.well-known/security.txt` on your domain, over HTTPS, as `text/plain` in UTF-8. It allows the request to that path to end in a redirect. You can redirect to the hosted file or copy it.

### Redirect to the hosted file

Redirect `https://<your-domain>/.well-known/security.txt` to the hosted file. It stays current and renews its expiry by itself.

<CodeGroup>
  ```nginx nginx theme={null}
  location = /.well-known/security.txt {
      return 302 https://app.pharussecurity.com/disclose/<your-slug>/security.txt;
  }
  ```

  ```apache Apache theme={null}
  Redirect 302 /.well-known/security.txt https://app.pharussecurity.com/disclose/<your-slug>/security.txt
  ```

  ```text Netlify theme={null}
  /.well-known/security.txt  https://app.pharussecurity.com/disclose/<your-slug>/security.txt  302
  ```

  ```js next.config.js theme={null}
  module.exports = {
    async redirects() {
      return [{
        source: '/.well-known/security.txt',
        destination: 'https://app.pharussecurity.com/disclose/<your-slug>/security.txt',
        permanent: false,
      }];
    },
  };
  ```
</CodeGroup>

You can leave **Canonical URL** empty: `Canonical` then names the hosted file, where the redirect ends. Or set it to `https://<your-domain>/.well-known/security.txt`, so the file names your domain.

### Copy the file

Copy the text from the **security.txt** card in **Settings → Disclosure** and serve it at `https://<your-domain>/.well-known/security.txt`.

Before you copy it, set **Canonical URL** to that address, so the copy names where it lives. Replace the copy before its `Expires` date, and again whenever you change your disclosure settings or publish your first TLP:WHITE advisory, which adds the `CSAF` line.

### Compare the two

| | Redirect | Copy |
| - | - | - |
| `Expires` | Rolls forward by itself | Fixed; replace the copy before it passes |
| Changes in **Settings → Disclosure** | Show within five minutes | Show when you replace the copy |
| The `CSAF` line | Appears by itself | Appears when you replace the copy |
| OpenPGP signature | Not possible | You can sign your copy |
| Where the file lives | On the Pharus host, reached from your domain | On your own host |
| Tools that don't follow redirects | Don't find it | Find it |

<Note>
  Setting **Canonical URL** also sets the publisher namespace of your CSAF advisories to your domain. Choose it before you publish your first advisory. See [publisher namespace](/api-reference/csaf-feed#publisher-namespace).
</Note>

RFC 9116 also allows a file at the top-level `/security.txt` for older tools, or a redirect from there to the `/.well-known/` one. When both exist, the `/.well-known/` file is the one that counts.

### Check it

```bash theme={null}
curl -sL https://<your-domain>/.well-known/security.txt
```

The output should be your file, with an `Expires` date in the future.

## Related

<CardGroup cols={2}>
  <Card title="Disclosure page" icon="globe" href="/disclosure/disclosure-page">
    The settings the file is generated from.
  </Card>

  <Card title="CSAF feed" icon="rss" href="/api-reference/csaf-feed">
    Where the `CSAF` line points.
  </Card>

  <Card title="Disclosure inbox" icon="inbox" href="/disclosure/inbox">
    Where reports from the contacts land.
  </Card>

  <Card title="Security advisories" icon="file-text" href="/disclosure/advisories">
    Publish the advisory that adds the `CSAF` line.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.