> 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-decide-what-to-build/signals/security-scanning.md).

# Security scanning

What scanning tells us about the code we depend on and about our own code.

Owner: Jeremy

We use [Aikido](https://help.aikido.dev/) to scan the code we depend on and our own code. A pentest covers the running product. [Tickets › Security](/engineering/development-process/how-to-build/tickets/security.md) says what a security ticket has to say.

## Rules

* A finding about a dependency carries a CVE or GHSA id. Anything else reporting that id is the same flaw.
* A finding about our own code carries no id. A person decides whether two of them are the same.
* One advisory in one repository is one ticket. A ticket is never a duplicate of its own parent or child.
* Every ticket Aikido files, and every ticket carrying the `Security` label, falls under [our security policies](https://app.eu.vanta.com/c/umh/employee/onboarding) (Vanta, UMH only) and the deadlines in them.
* By that deadline, the ticket has been accepted as work or closed with a reason.
* If a real issue will not be fixed in time, ask the CTO to accept the risk or to agree on a plan.
* A ticket is closed either by doing the work, or by cancelling it: saying it is already fixed, not a real problem, or not reaching anything we ship.
* Only write `Fixes` when the upgrade reaches the version that clears the advisory.

## What counts as one finding

**A security issue can come from our code or from the container we build from it. Both are one ticket.**

**Split a finding that arrives covering several repositories at once.** Most sources file one ticket per repository already. Where one does not, the parent keeps the finding across every repository that ships the package. Each child is tied to the one repository where a pull request can fix it. Read the advisory set at the version each repository actually has, so a parent and a child can correctly name different advisories.

**Marking a ticket a duplicate cancels it.** Point a second report of the same advisory at the oldest ticket still open. Point it at a closed one and both end up closed with nothing fixed.

## Deadlines

**A signal can usually wait. A security signal comes with a deadline.** A customer request or a usage report sits in Ideas until someone gets to it. A security ticket's deadline runs from the day the issue was found.

**Today a security ticket has 30 days at critical and at high, 60 at medium and 90 at low.** [Our security policies](https://app.eu.vanta.com/c/umh/employee/onboarding) (Vanta, UMH only) set these and Vanta keeps the clock. Read the deadline off the ticket rather than counting days yourself.

## How a ticket closes

**Aikido closes the tickets it filed**, once a scan of the default branch no longer finds the advisory. It checks every eight hours ([Aikido's documentation](https://help.aikido.dev/getting-started/task-management-systems/advanced-functionalities/auto-close-linear-tasks-when-aikido-issues-are-resolved)).

**Tickets we wrote ourselves close through the `Fixes ENG-NNNN` link in their own pull request.** A child we split out of a finding, with no pull request behind it, stays open until someone closes it by hand.

**An upgrade that stops below the clean version gets the ticket linked without `Fixes`.** [Linear moves the ticket by itself](/engineering/development-process/how-to-ship.md#ticket-states-in-linear) when the pull request merges, so `Fixes` on a partial upgrade would end the deadline with the advisory still live.

### The automatic upgrade

**Renovate opens the pull request that upgrades a vulnerable dependency.** Link it to the ticket yourself; nothing links them for you.

**A Renovate pull request carries the `renovate/` branch prefix.** Titles are configurable and change.

**Renovate waits until a new version is a few days old before it opens the pull request.** No pull request today does not mean none is coming.

**Renovate opens no pull request in two cases:**

* An `// indirect` requirement in `go.mod`. Whatever pulls it in has to be upgraded instead.
* An npm package in the Management Console. Its `renovate.json` enables `dockerfile`, `gomod` and `github-actions` only, so npm versions there are set by hand.


---

# 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-decide-what-to-build/signals/security-scanning.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.
