Security and privacy¶
This page is about the website at dennis-otto.github.io itself: what it does in your browser, how a change reaches it, where its trust boundaries lie and which risks remain. Each project describes its own software on its own website. SECURITY.md says what happens with a report and how the repository keeps itself secure.
What you can expect¶
- Static pages over HTTPS. GitHub Pages serves the pages as files; no code of the website runs on a server. It answers an
http://address with a redirect tohttps://, and tells your browser to use nothing but HTTPS for the address for a year (HSTS). - No cookies, analytics, advertising or sign-in, and no form that sends what you type anywhere.
- Fonts and scripts from this address. While the website is built, the privacy plugin of Material for MkDocs downloads the Roboto fonts from Google Fonts and the Mermaid script for diagrams from unpkg, and the website serves them itself, under
/assets/external/. Reading a page asks neither Google nor unpkg. - The search stays in your browser. Its index is a file of the website, which holds the pages of every project website too, and what you type into the search box stays on the page.
- Two small entries in your browser. Its local storage keeps whether the pages are light or dark (
/.__palette), and its session storage keeps the number of public repositories in the header until the tab closes (/.__source). Neither is sent anywhere. The language is part of the address,/de/for German, and isn't stored. - One request to another server. The header asks
api.github.comfor the number of public repositories of Dennis-Otto, at most once per browser tab, so GitHub sees your IP address and that you visit a website at this address. An outdated browser withoutResizeObserver, such as Safari before version 13.1, also loads a small script from unpkg that adds it. - Links that leave the website. The buttons of the projects lead to HACS through my.home-assistant.io, to the Nextcloud App Store and to GitHub, where their own privacy rules apply.
GitHub, which hosts the website, logs the IP address of every visitor for security purposes, as About GitHub Pages says; the GitHub General Privacy Statement applies to it.
Trust boundaries¶
---
config:
flowchart:
wrappingWidth: 400
---
flowchart TB
accTitle: The trust boundaries of the website
accDescr: Six boundaries. 1, a pull request reaches main only through the ruleset of main and every required check. 2, the Docs workflow builds the website from main with tools from PyPI that are pinned by their hashes, and downloads the fonts from Google Fonts, Mermaid from unpkg and the search indexes of the project websites while it builds. 3, its deploy job alone publishes the website, in the environment github-pages, which accepts main alone, with a short-lived OIDC token. 4, GitHub Pages serves this website at the root of dennis-otto.github.io, on the same origin as the project websites, which their own repositories build and publish. 5, your browser gets the pages over HTTPS and asks api.github.com for the number of public repositories. 6, the install links lead to HACS, the Nextcloud App Store and GitHub.
subgraph repo ["This repository"]
pr(["A pull request"])
checks{{"The ruleset of main:<br>every required check"}}
main["main"]
build(["Docs workflow:<br>mkdocs build --strict"])
deploy(["Its deploy job"])
end
pypi[("PyPI:<br>tools pinned by hash")]
downloads[("Google Fonts and unpkg:<br>fonts and Mermaid")]
environment{{"Environment github-pages:<br>main alone, OIDC"}}
subgraph origin ["One origin: https://dennis-otto.github.io"]
root["This website at /<br>robots.txt, security.txt,<br>icons, 404 page"]
projects["The project websites<br>/ha-autodarts/ … /repo-blueprint/"]
end
others(["Their own repositories<br>and workflows"])
browser(["Your browser"])
api[("api.github.com")]
stores["HACS · Nextcloud App Store · GitHub"]
pr -- "1" --> checks --> main --> build
pypi -- "2 · hashes checked" --> build
downloads -- "2 · at build time" --> build
projects -- "2 · search indexes at build time" --> build
build --> deploy -- "3" --> environment --> root
others -- "4" --> projects
root & projects -- "5 · HTTPS, HSTS" --> browser
browser -- "5 · number of repositories" --> api
browser -- "6 · install links" --> stores
classDef bot fill:#526cfe2e,stroke:#526cfe,stroke-width:2px
classDef person fill:#f59e0b2e,stroke:#f59e0b,stroke-width:2px
classDef done fill:#16a34a2e,stroke:#16a34a,stroke-width:2px
class build,deploy,others bot
class pr,browser person
class root,projects done
- A pull request →
main. A change reachesmainonly through a pull request that is up to date withmainand passes every required check, squashed into one signed commit. The ruleset ofmainhas no exceptions, not even for administrators. Among the checks, docs builds the website strictly, so that a link or an anchor that leads nowhere fails it; CodeQL and actionlint examine the workflows, Gitleaks the secrets and the dependency review new dependencies. - Third-party code → the build. The Docs workflow installs MkDocs, Material for MkDocs and their plugins from PyPI with
pip install --require-hashes -r .github/docs-requirements.txt, so pip refuses every file whose SHA-256 hash differs from the lock file. The actions are pinned to commit hashes. While the website is built, the privacy plugin downloads the fonts from Google Fonts and Mermaid from unpkg, asmermaid@11, the newest release of version 11; these downloads have no pinned hash. The hooks of the website download the search index of each project website at the address too and add its titles and excerpts to the search of this website. Harden-Runner records the network traffic of every job. - The build → GitHub Pages. The jobs that build the website hold a token that can only read. The deploy job alone may publish: it runs in the environment
github-pages, which accepts runs onmainalone, and identifies its workflow with an OIDC token that GitHub issues for that one run, instead of a stored secret. No branch holds the published website. - The websites of the projects → the same address. Autodarts for Home Assistant, Paperless Sync, Paperless Unified Search, the issue assistant and Repo Blueprint live in folders of the address, and each is built and published by its own repository, with its own checks. For your browser, they and this website are one origin,
https://dennis-otto.github.io. This repository serves the root of the address:robots.txt,security.txtand the icons for all of them, and the 404 page for every address outside the folders of the projects, whose websites answer a missing page with their own. - The website → your browser. The pages travel over HTTPS, and the only other server that a page asks is
api.github.com, for the header. - The install links → other services. HACS, the Nextcloud App Store and GitHub deliver the software of the projects. The SECURITY.md of each project says how to verify its releases.
Threats and countermeasures¶
| Threat | Countermeasure | Evidence |
|---|---|---|
| A tampered build tool on PyPI | pip installs only files with the hash of the lock file. A new version arrives with the update pull request of the blueprint and passes every check here; in repo-blueprint, Renovate proposes it a week after its release at the earliest, unless it fixes a vulnerability | .github/docs-requirements.txt, which the blueprint keeps current; stacks/docs/requirements-docs.txt and .github/renovate-blueprint.json5 in repo-blueprint |
| A changed font or Mermaid release, downloaded while the website is built | The download runs over HTTPS on a runner of GitHub, never in your browser, and Harden-Runner records it. Mermaid has no pinned version yet, which Residual risks describes | /assets/external/ of the website, .github/workflows/docs.yml |
| A harmful change to a page, a hook or a workflow | The ruleset of main without exceptions, every required check and a squashed, signed commit |
.github/repository.toml |
| An unauthorized deployment | The deploy job alone publishes, in the environment github-pages, which accepts main alone, with a short-lived OIDC token; no key or token for publishing is stored anywhere |
.github/workflows/docs.yml, the branch policy of the environment |
| Someone on the network reads or changes a page | HTTPS, which GitHub Pages enforces, and HSTS for a year | the header Strict-Transport-Security: max-age=31556952 |
| A link to another website breaks or changes hands | Every address of a project card starts with https://. The Links workflow checks the links of the pages and of the README, which lists every address of the cards, every week, and opens an issue for a broken one. It leaves out the redirect of my.home-assistant.io behind the HACS button, as lychee.toml says |
URL in .github/mkdocs_project.py, .github/workflows/links.yml, lychee.toml |
A text of projects.toml breaks a card or the structured data of the home page |
Brackets in the texts of a card are escaped, and no text can end the script of the structured data | test_a_card_escapes_brackets_in_its_texts and test_no_text_of_the_catalog_ends_the_script_of_the_structured_data in tests/test_mkdocs_project.py |
| The search index of a project website carries markup or a script into the search of this website, or can't be downloaded | The search takes the plain text of every title and excerpt of a project, escaped, and leaves out an index that isn't one. A project whose index can't be downloaded stays out of the search until the next build, which passes | test_an_excerpt_is_the_plain_text_of_a_section, test_a_broken_search_index_is_named and test_the_search_of_the_address_adds_every_project_website in tests/test_mkdocs_project.py |
| A compromised project website on the shared origin | Nothing to steal: no website of the address sets a cookie or has a sign-in, and the browser's storage holds the color scheme and the number of repositories | the headers and pages of the live websites |
Residual risks¶
- The root of the address. A service worker registered by this website could control every page of dennis-otto.github.io, the project websites included, while a project website can register one for its own folder only. This website registers none. That makes a change to this repository the most sensitive of them all.
- One origin for every website. A flaw in any of them, such as a script that a compromised build tool adds to its pages, reaches the others in your browser, because one origin shares the browser's storage and lets one page script another.
- Downloads at build time. The fonts and Mermaid are downloaded anew in every build, without a pinned hash, and Mermaid follows the newest release of version 11. A harmful release on unpkg would reach the website with the next change of
main; only a page with a diagram, such as this one, loads Mermaid. - GitHub. GitHub hosts the website, the repository and the request of the header, and logs the IP addresses of the visitors. Whoever controls the GitHub account Dennis-Otto can change every website of the address.
- Material for MkDocs. Material for MkDocs went into maintenance mode with version 9.7.0 in November 2025, with critical bug fixes and security updates promised for at least 12 months, until about November 2026. After that, a vulnerability in its JavaScript may stay unfixed.
Report a vulnerability¶
Please don't open a public issue for a suspected vulnerability. Report it privately to the repository that builds the affected website; SECURITY.md says what happens next and how fast.
| Website | Report privately |
|---|---|
| This website, the root of the address, and anything you can't place | dennis-otto.github.io |
| Autodarts for Home Assistant | ha-autodarts |
| Paperless Sync | paperless-sync |
| Paperless Unified Search | paperless-unified-search |
| Issue assistant | issue-assistant |
| Repo Blueprint and the dashboard | repo-blueprint |
security.txt names the first of these forms for the whole address, and this page as its policy.
Decisions¶
The decision records explain the decisions that shape the website and its repository, each with its reasons.