> For the complete documentation index, see [llms.txt](https://engineering.umh.app/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://engineering.umh.app/engineering/development-process/how-to-build/tickets/security.md).

# Security

What counts as a security issue, where its ticket goes, and how we tell customers about the fix.

Owner: Jeremy

This page covers a security issue once someone has found it. [Security scanning](/engineering/development-process/how-to-decide-what-to-build/signals/security-scanning.md) says where findings come from, what counts as one finding, what deadline a ticket has and how it closes; [the security coding standard](/engineering/development-process/how-to-build/coding-standards/architecture/security.md) says how we avoid them in the first place; [Dependencies](/engineering/development-process/how-to-build/tickets/security/dependencies.md) says what a vulnerable dependency adds.

## Rules

* Every potential security issue, including a vulnerable dependency, goes under the "Security" sub-ticket.
* A security ticket carries a [CWE](https://cwe.mitre.org/) and an [ASVS](https://owasp.org/www-project-application-security-verification-standard/) requirement where one names the defect. "None" and one sentence saying why is a valid answer.
* Severity sets how long the ticket has. Whether an issue is exploitable today can move the severity up or down one level.
* The Code Owner of the affected code checks whether an issue is real.
* A scanner tells you a version to upgrade to. Check it against the advisory database, which can list that version as still affected.
* We fix known weaknesses and vulnerable dependencies without first proving that we are exposed.
* Check that an automatic upgrade arrived before the deadline.
* Fix a finding that spans repositories in the child tickets.
* An attack that is happening now follows our [incident policies](https://app.eu.vanta.com/c/umh/employee/onboarding) (UMH only).
* Every security fix the customer can notice goes into the [changelog](/engineering/development-process/how-to-ship/changelog.md).

## Severity

**The Code Owner writes down why the severity moved.** An issue that a pentest could use today moves up. An issue that only a future change could make exploitable, such as a vulnerable function in a dependency that we don't call, can move down.

**Proving that we are not exposed is expensive.** The proof only lasts until the next change calls the vulnerable code.

## The description

**The title is `[SECURITY] <CVE, GHSA id or CWE>: <what goes wrong> — <repository> (<Severity>)`.** Leave the repository out when the ticket covers several. A GHSA id is in that slot because some advisories never get a CVE.

**The severity in brackets is the official rating, which never moves.** Ours, after exploitability has moved it, lives in Linear's priority field. A ticket titled Critical that sits at Low priority is therefore correct.

**A finding in our own code carries no official rating.** Where a scanner put a level on it, repeat the level and mark it scanner-assigned.

**Every field in the** [**template**](#template) **is filled before anyone works the ticket.** A field nobody could establish says so.

**Read the answer out of the threat model, then the product documentation, then the repository's own code.** "Cannot be established" is an answer only when the repository could not be read.

**Exploitable today is established from configuration.** A one-off probe of live behaviour measures the deployment in front of you. It stops being true at the next change.

**Reachable through names a feature, or says nothing the customer runs.** A flaw a customer could reach by switching a feature on is reachable through that feature, whether or not anyone has switched it on. The [changelog](/engineering/development-process/how-to-ship/changelog.md#security-fixes) entry tells them which customers it concerned.

**One upgrade can fix several advisories. The title names the worst one.** Say how many others ride along. Put the full list in a comment.

**The** [**CWE**](/engineering/development-process/how-to-build/tickets.md#public-names) **goes in the pull request description, not in the code.**

## The Security label

**The Security label in Linear makes Vanta, our compliance tool, track the ticket.** [Security scanning](/engineering/development-process/how-to-decide-what-to-build/signals/security-scanning.md#deadlines) says what deadline it then has.

**Anyone can file a suspected security issue without the Security label.** Such a ticket starts no clock. The [Code Owner](/engineering/product-engineer/code-owner.md) of the affected code checks how serious it is. They ask the CTO when unsure. If the issue is real, they add the Security label and set the priority: Urgent for a critical issue, otherwise High, Medium or Low. If the issue isn't real, they close the ticket with the reason.

**Every ticket under a security ticket carries the Security label as well.**

**Aikido, our security scanner, files a ticket for each issue it finds, with the Security label already set. Keep the label on.** Vanta reads Aikido's results directly, so the clock starts when Aikido found the issue. The clock runs on Aikido's severity. If Aikido is wrong about an issue, mark it as ignored in Aikido and write why in the ticket.

## Telling customers

**Customers learn about security from three places: the** [**changelog**](/engineering/development-process/how-to-ship/changelog.md)**, our public** [**threat model**](https://docs.umh.app/management-console/security/threat-model) **and our** [**Trust Center**](https://trust.umh.app)**.** A message to a customer links the changelog entry and adds only what is specific to that customer.

## Template

```markdown
**Name:** <CWE> · <ASVS requirement, for example v5.0.0-2.4.1, where one names the defect> · <or "none" and one sentence saying why>
**Severity:** <the level we use, the same as Linear's priority> · <the official rating, and why we moved it, for example "official Critical, downgraded: the vulnerable function is never called">
**Repository:** <name the repository this ticket is tied to. A ticket covering several names every one of them. Never write a count>
**Reachable through:** <the feature a user could have switched on, named as our docs name it> · <or "nothing the customer runs", which means no changelog entry>
**Found by:** <link to the review thread, the pentest finding and its number, the Aikido finding, or the lines of code>

## What an actor could do
<One sentence, with the actor from the threat model.>

## Exploitable today
<yes / no / cannot say> — <how you know. If you reasoned it out rather than read it, name the one question that would settle it.>
```

A vulnerable dependency also fills the block on [Dependencies](/engineering/development-process/how-to-build/tickets/security/dependencies.md#template).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://engineering.umh.app/engineering/development-process/how-to-build/tickets/security.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
