Owner: the founder. Approved: 2026-10-08. Review: annually, and on any significant change to the scanners, the gate or the hosting.
Scope: flaws in our own code, in the libraries and container images we ship, in
the application server's operating system, and in the services we depend on.
How code is written and gated is secure-development.md; an exploited flaw is
an incident and goes to docs/legal/incident-response-plan.md the same day.
| Source | What it covers | When it runs | Effect |
|---|---|---|---|
trivy fs (pre-push gate, dependencies stage) |
Advisories against the locked Python dependencies, and Dockerfile misconfiguration | Every push | A CRITICAL with a released fix refuses the push. A HIGH is printed, not gating. Advisories with no fix are not reported (--ignore-unfixed) |
ruff with the S (flake8-bandit) rules (lint stage) |
Insecure patterns in our code | Every push | Refuses the push |
gitleaks (secrets and history stages) |
Credentials in the branch and in the whole history | Every push | Refuses the push |
API fuzz (api-fuzz stage) |
Crashes and 5xx on the public HTTP surface | Every push | Refuses the push |
| Host updates | Ubuntu security updates on the application server, via unattended-upgrades (set up by infrastructure/harden_v2.py; nothing re-checks that it is still on) |
Daily | Applied automatically; automatic reboot is off, so a kernel update waits for a manual reboot |
| Container rebuild | Every deploy rebuilds the application image and pulls the current tags of the Caddy, Redis and ClamAV images (--pull always) |
Every deploy | Picks up patched packages published under those tags; no image is scanned (§5) |
| Vendor notices | Security notices from Hetzner, Neon, Cloudflare and the other sub-processors | As sent | Reach the founder as the holder of each account; no aggregated feed |
| Reports from outside | security@ataski.com, published in /.well-known/security.txt |
Any time | Triaged the same day |
The pre-push gate is scripts/check.py, run by the git pre-push hook
(ADR-0119). It runs on the founder's machine: there is no independent CI, and
git push --no-verify skips it (change-management.md §7). The pre-commit
hooks in .pre-commit-config.yaml were found not to be running on the
workstation; reinstalling them is in progress, and until then the pre-push gate
is the only automatic scan.
Severity starts from the advisory's CVSS base score and is then adjusted, in writing, for our deployment: is the vulnerable code reachable, from where, and could it reach Customer Data or another workspace? Anything that can reach Customer Data or cross a tenant boundary is Critical, whatever the score.
The clock starts when the founder learns of the finding.
| Severity | Typical CVSS | Mitigate | Fix |
|---|---|---|---|
| Critical | 9.0 – 10.0, or reaches Customer Data | within 72 hours — flag off, kill switch, or take the affected surface offline | within 7 days |
| High | 7.0 – 8.9 | — | within 30 days |
| Medium | 4.0 – 6.9 | — | within 90 days |
| Low | below 4.0 | — | at the next quarterly review: fix, or accept with a written reason |
Evidence of exploitation turns any finding into an incident, triaged the same
day. These deadlines are what one operator can keep; they are not yet measured.
The quarterly self-review (docs/security/evidence-checklist.md §4) records
each open finding with its dates, which is where time-to-fix will be shown from.
.trivyignore with its reason on the line above. An entry
older than 90 days fails the gate (tests/test_trivy_ignore_policy.py), so
every waiver expires and must be re-decided or fixed. The file is empty today.information-security.md §6). The
accepted risk also goes into docs/security/risk-register.md.docs/security/pentest-checklist.md is the scope and the self-test until one
is; /trust says so.trivy
output.ruff's security rules and no DAST beyond the API fuzz.