From f2fb7adf556ed3f90ea187ae2accd5fcc1ae7af2 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Thu, 25 Jun 2026 00:30:16 -0400 Subject: [PATCH] docs: add cooldown Also ran a review with Opus and fixed a few typos. Assisted-by: ClaudeCode:claude-opus-4.8 Signed-off-by: Henry Schreiner --- docs/guides/security.md | 71 +++++++++++++++++++++++++++++++++++------ 1 file changed, 62 insertions(+), 9 deletions(-) diff --git a/docs/guides/security.md b/docs/guides/security.md index d51e7eff..c5dd4b50 100644 --- a/docs/guides/security.md +++ b/docs/guides/security.md @@ -7,13 +7,13 @@ short_title: Security Supply-chain and CI security are increasingly important for scientific Python projects; new attacks are targeting smaller packages than ever before thanks to the ease with which exploits can be found and utilized with AI. The first six -months of 2026 had 4.5x the malitoius package volume of _all_ of 2025[^1]. +months of 2026 had 4.5x the malicious package volume of _all_ of 2025[^1]. [^1]: -Most of these attacks strung together smaller vulerabilties into something +Most of these attacks strung together smaller vulnerabilities into something exploitable, often in CI like GitHub Actions. Once in, the attacks upload -malitious packages that spread the attack via PyPI or NPM. +malicious packages that spread the attack via PyPI or NPM. This page has recommendations for keeping your repository and its automation secure. This will never be complete, but even a few small steps can make your @@ -22,22 +22,22 @@ code much more secure. ## GitHub Actions {rr}`SEC001` GitHub Actions workflows are a common source of security issues, -due to how commonly it is used, and it's original design being focused on ease +due to how commonly it is used, and its original design being focused on ease of use and convenience. Common security problems: * Action moving references, like `@v1`, or tags, like `@v1.0.1`, can be pushed - if an attacker comprimizes the action repository you are using. If you use + if an attacker compromises the action repository you are using. If you use full 40 character SHA's, these cannot be modified. (Official actions are likely okay, but important for third party actions). There's even a GitHub setting to require this. It's conventional to include the tag as a trailing comment. * Action SHA references can be added by a fork. If you make a fork of - `actions/checkout`, you can reference _your_ SHA via - `actions/checkout@`. Only accept SHAs you have verified or a tool (like - dependabot) produce. If you use Zizmor, it can also verify that an SHA matches - a tag, tags cannot be pulled from a fork. + `actions/checkout`, you can reference _your_ SHA via `actions/checkout@`. + Only accept SHAs you have verified or a tool (like dependabot) produces. If + you use Zizmor, it can also verify that an SHA matches a tag, tags cannot be + pulled from a fork. * Caching is dangerous. Attackers can poison an unrelated cache. Avoid caching in your release jobs. * `pull_request_target` is really dangerous. Attackers can use it to poison @@ -108,3 +108,56 @@ GitHub Action can upload its findings to GitHub's code scanning dashboard. You can silence individual findings with `# zizmor: ignore[rule]` comments, or collect them in a [`zizmor.yml`](https://docs.zizmor.sh/configuration/) config file. + +## Cooldowns + +Often malicious code is found and removed from indexes in a day or two. Adding +a cooldown can protect you from some of these large scale attacks that are +caught quickly. There's a problem though; this also means you'll take longer +to get fixes for known vulnerabilities. Also, if everyone does this, it could +just delay discovering attacks. So try to strike the appropriate balance. + +[Dependabot's cooldown][dependabot-cooldown] can do that for you (GitHub +Actions, pre-commit, lock files for most languages): + +```yaml +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + cooldown: + default-days: 3 +``` + +The `cooldown` block goes inside each `updates:` entry; repeat it for every +ecosystem you configure. + +For uv, you can add hard-coded config with [`exclude-newer`][uv-exclude-newer]: + +```toml +[tool.uv] +exclude-newer = "3 days" +``` + +You can also [override or skip specific packages][uv-exclude-newer-package]. + +For uv or pip, you can set environment variables: + +```bash +PIP_UPLOADED_PRIOR_TO="P3D" +UV_EXCLUDE_NEWER="3 days" # P3D works too +``` + +There are also matching command line arguments for both +([`--uploaded-prior-to`][pip-uploaded-prior-to]/[`--exclude-newer`][uv-exclude-newer]). +You can also use dates instead of durations, which works much like lockfiles +without the churn. Use a full date, including time, like +`"2026-01-01T00:00:00Z"`, to get matching behavior in pip and uv, otherwise they +will be one day off each other. + +[dependabot-cooldown]: https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#cooldown +[uv-exclude-newer]: https://docs.astral.sh/uv/reference/settings/#exclude-newer +[uv-exclude-newer-package]: https://docs.astral.sh/uv/reference/settings/#exclude-newer-package +[pip-uploaded-prior-to]: https://pip.pypa.io/en/latest/user_guide/#filtering-by-upload-time