> ## 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.

# CSAF feed

> The public CSAF 2.0 endpoints for your TLP:WHITE advisories: provider metadata, index.txt, changes.csv, documents and hash files.

<Info>
  **Plans:** Every plan, and Free: published advisories stay in the feed. **Who:** public; no sign-in or token.
</Info>

Every workspace has a public CSAF 2.0 feed of its published TLP:WHITE [advisories](/disclosure/advisories). Your customers' security tools and CSAF aggregators read it to learn, for each of your product versions, whether a vulnerability affects it. The feed serves the same documents as your public advisories page.

## Endpoints

All endpoints answer `GET` without authentication. The base is `https://app.pharussecurity.com/csaf/<your-slug>`.

| Path | Content type | Returns |
| - | - | - |
| `/csaf/<your-slug>/provider-metadata.json` | `application/json; charset=utf-8` | The provider metadata |
| `/csaf/<your-slug>/white/index.txt` | `text/plain; charset=utf-8` | Every document's path, one per line |
| `/csaf/<your-slug>/white/changes.csv` | `text/csv; charset=utf-8` | Every document's path with its last change |
| `/csaf/<your-slug>/white/<yyyy>/<file>.json` | `application/json; charset=utf-8` | One CSAF document |
| `/csaf/<your-slug>/white/<yyyy>/<file>.json.sha256` | `text/plain; charset=utf-8` | Its SHA-256 hash |
| `/csaf/<your-slug>/white/<yyyy>/<file>.json.sha512` | `text/plain; charset=utf-8` | Its SHA-512 hash |

Only the `white` directory exists. TLP:GREEN, AMBER and RED advisories are never served here.

Every successful response carries these headers:

```http theme={null}
Access-Control-Allow-Origin: *
Cache-Control: public, max-age=300, stale-while-revalidate=60
X-Content-Type-Options: nosniff
```

A new version can therefore take up to five minutes to show. An unknown slug, a directory other than `white` or a file that isn't published returns `404` with the body `Not found`, as `text/plain`, with `Cache-Control: no-store`.

## provider-metadata.json

The entry point for CSAF tools. It is served for every workspace, also before you have published anything.

```json theme={null}
{
  "canonical_url": "https://app.pharussecurity.com/csaf/<your-slug>/provider-metadata.json",
  "distributions": [
    {
      "directory_url": "https://app.pharussecurity.com/csaf/<your-slug>/white/"
    }
  ],
  "last_updated": "2026-10-12T09:14:03.000Z",
  "list_on_CSAF_aggregators": true,
  "metadata_version": "2.0",
  "mirror_on_CSAF_aggregators": true,
  "publisher": {
    "category": "vendor",
    "name": "Nordlys Elektronikk AS",
    "namespace": "https://nordlys.no",
    "contact_details": "Security contact: security@nordlys.no"
  },
  "role": "csaf_publisher"
}
```

| Field | Value |
| - | - |
| `canonical_url` | This file's own address. |
| `distributions` | One directory: the `white` directory. It has no listing page of its own; `index.txt` and `changes.csv` list its files. |
| `last_updated` | When you last published a TLP:WHITE version, or when the workspace was created if you haven't. |
| `list_on_CSAF_aggregators`, `mirror_on_CSAF_aggregators` | Both `true`: aggregators may list the feed and mirror its documents. |
| `publisher` | Your company as a `vendor`, with the [publisher namespace](#publisher-namespace) and a contact: the **Public contact email** from **Settings → Disclosure**, or, when that is empty, the **Security contact email** from **Settings → Company**. |
| `role` | `csaf_publisher`. |

The metadata lists no OpenPGP keys, and the documents aren't OpenPGP-signed: there are no `.asc` files. A tool that requires signatures reports the documents as unsigned. Integrity comes from the hash files and HTTPS.

## index.txt

One `<yyyy>/<file>.json` path per line, relative to the directory, newest first:

```text theme={null}
2026/<your-slug>-2026-0002.json
2026/<your-slug>-2026-0001.json
```

The body is empty when nothing is published.

## changes.csv

One line per document, newest change first, with no heading row. Each line holds the path and the document's `current_release_date`, both quoted:

```text theme={null}
"2026/<your-slug>-2026-0002.json","2026-10-12T09:14:03.000Z"
"2026/<your-slug>-2026-0001.json","2026-09-30T13:02:44.000Z"
```

Poll this file to see what changed since your last run.

## Documents

`GET /csaf/<your-slug>/white/<yyyy>/<file>.json` returns the latest published version of one advisory, byte for byte the document that was hashed when it was published.

* **File name:** the tracking ID in lower case, with every run of characters other than `a`–`z`, `0`–`9`, `+` and `-` replaced by `_`, then `.json`. `NORDLYS-2026-0001` becomes `nordlys-2026-0001.json`.
* **Folder:** the year of the advisory's first publication (`initial_release_date`).
* **Versions:** a new version replaces the file at the same address. Superseded versions aren't in the feed; your team downloads them from the advisory's **Releases** tab.
* **Headers:** besides the common ones, `ETag` is the document's SHA-256 in quotes, and `Last-Modified` is when this version was published.

Each document is a CSAF 2.0 `csaf_vex` document in English:

| Part | What Pharus writes |
| - | - |
| `document.publisher` | The same publisher as in the provider metadata. |
| `document.distribution.tlp` | Label `WHITE`, with the FIRST TLP page as `url`. |
| `document.tracking` | The tracking ID, status `final`, a semantic version (`1.0.0`, then `1.1.0` for an update or `1.0.1` for a correction), the first and current release dates, the full revision history, and `Pharus` as the generator. |
| `document.references` | A `self` reference to this document's feed address, and the references you added. |
| `document.acknowledgments` | The names you credited. |
| `product_tree` | Your company, then each product family, then each product version. |
| `vulnerabilities` | Per vulnerability: the CVE or other IDs, a description, the product status of every version, justification flags and impact statements for not-affected versions, remediations for affected ones, exploit status from CISA KEV or ENISA EUVD, and references. |

Every published version has passed the CSAF 2.0 schema and the VEX profile tests.

## Hash files

`<file>.json.sha256` and `<file>.json.sha512` hold the hex digest of the document, two spaces and the file name, in the format `sha256sum` and `sha512sum` read:

```text theme={null}
9f2c4a…e41a  <your-slug>-2026-0001.json
```

## Publisher namespace

CSAF identifies a document by its publisher namespace together with its tracking ID. Pharus sets the namespace from **Settings → Disclosure**:

* With a **Canonical URL** set, the namespace is that URL's origin, for example `https://nordlys.no`.
* Without one, it is `https://app.pharussecurity.com/csaf/<your-slug>`.

The namespace is written into each version as it is published. Set **Canonical URL** before you publish your first advisory and leave it, so every version carries the same namespace.

## Read the feed

Give your customers the provider metadata address, or let their tools discover it. A CSAF tool looks for a provider's metadata at `https://<domain>/.well-known/csaf/provider-metadata.json`, in the `CSAF` field of the domain's security.txt, or through DNS. Pharus writes the `CSAF` field into your [security.txt](/api-reference/security-txt), so once you serve that file from your own domain, tools given your domain can follow it to the feed.

A typical client:

1. Reads `provider-metadata.json` and takes the `directory_url`.
2. Reads `changes.csv` and picks the paths changed since its last run.
3. Downloads each document and checks it against its `.sha256` or `.sha512` file.

The same by hand:

```bash theme={null}
BASE="https://app.pharussecurity.com/csaf/<your-slug>/white"
curl -s "$BASE/changes.csv"
curl -sO "$BASE/2026/<your-slug>-2026-0001.json"
curl -sO "$BASE/2026/<your-slug>-2026-0001.json.sha256"
sha256sum -c <your-slug>-2026-0001.json.sha256
```

The endpoints allow requests from any origin, so tools that run in a browser can read them too.

## Advertise the feed

* **security.txt.** The `CSAF` line appears by itself once you publish a TLP:WHITE advisory. Serve the file from your own domain. See [security.txt](/api-reference/security-txt).
* **The advisories page.** `https://app.pharussecurity.com/disclose/<your-slug>/advisories` links "Machine-readable feed (CSAF)" and declares the provider metadata as its JSON alternate, as each advisory page does for its own document.
* **Your customers.** Put the provider metadata address in your product documentation, security page or customer agreements, where their security teams look for it.

## Related

<CardGroup cols={2}>
  <Card title="Security advisories" icon="file-text" href="/disclosure/advisories">
    Draft and publish the documents the feed serves.
  </Card>

  <Card title="security.txt" icon="file-text" href="/api-reference/security-txt">
    The file that points tools to the feed.
  </Card>

  <Card title="Disclosure page" icon="globe" href="/disclosure/disclosure-page">
    Canonical URL and the other disclosure settings.
  </Card>

  <Card title="API introduction" icon="code" href="/api-reference/introduction">
    The rest of the Pharus API.
  </Card>
</CardGroup>


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