From cb5736ea3e04d22b529ef75707cbc266dc7ff8f1 Mon Sep 17 00:00:00 2001 From: Jeffrey 'Alex' Clark Date: Thu, 9 Apr 2026 12:26:29 -0400 Subject: [PATCH 01/20] Add INCIDENT_RESPONSE.md --- .github/INCIDENT_RESPONSE.md | 441 +++++++++++++++++++++++++++++++++++ 1 file changed, 441 insertions(+) create mode 100644 .github/INCIDENT_RESPONSE.md diff --git a/.github/INCIDENT_RESPONSE.md b/.github/INCIDENT_RESPONSE.md new file mode 100644 index 00000000000..03371c4f3b7 --- /dev/null +++ b/.github/INCIDENT_RESPONSE.md @@ -0,0 +1,441 @@ +# Incident Response Plan — Pillow + +This document describes how the Pillow maintainers detect, triage, fix, communicate, and +learn from security incidents. It supplements the existing [Security Policy](SECURITY.md) +and [Release Checklist](../RELEASING.md). + +--- + +## 1. Preparation + +Maintaining readiness before an incident occurs reduces response time and errors under pressure. + +### 1.1 Version Support Matrix + +Only the following branches receive security fixes. Reporters should verify their affected +version before filing; maintainers should cherry-pick fixes only to supported branches. + +| Branch | Status | Notes | +|---|---|---| +| `main` | ✅ Active development | Always patched | +| Latest stable (e.g. `11.x`) | ✅ Security fixes | Current quarterly release series | +| Previous stable (e.g. `10.x`) | ⚠️ Critical only | One release series back; Critical CVEs only | +| Older branches | ❌ End of life | No security support; users must upgrade | + +> Update this table with each quarterly release. + +### 1.2 Team Readiness + +- Maintain a private list of current maintainer contact details (GitHub handles, email, + Mastodon) in a location accessible to all maintainers (e.g. a pinned private team + discussion or the Tidelift maintainer portal). +- Ensure at least two maintainers have admin access to: + - The GitHub repository (to manage Security Advisories) + - The [PyPI Pillow project](https://pypi.org/project/Pillow/) (to yank releases) + - The Tidelift maintainer portal +- Rotate and audit PyPI API tokens and GitHub Actions secrets at least once per year, + and immediately after any maintainer leaves the project. + +### 1.3 Annual Readiness Review + +Once per year (suggested: at the January quarterly release), maintainers should: + +1. Re-read this document and update any stale content (version table, contacts, tooling). +2. Verify the GitHub private security advisory flow still works (open and close a test advisory). +3. Confirm PyPI yank access is functional. +4. Review Dependabot and CodeQL alert settings are enabled on the repository. + +--- + +## 2. Scope + +This plan covers: + +| Incident type | Examples | +|---|---| +| Vulnerability in Pillow's own Python or C code | Buffer overflow in an image decoder, integer overflow in `ImagingNew` | +| Vulnerability in a bundled or wheel-shipped C library | libjpeg, libwebp, libtiff, libpng, openjpeg, libavif | +| Supply-chain compromise | Malicious commit, stolen maintainer credentials, tampered PyPI wheel | +| CI/CD or infrastructure compromise | GitHub Actions secret leak, Codecov breach, PyPI token exposure | +| Critical non-security regression | Data-loss bug shipped in a release, crash on all supported platforms | + +--- + +## 3. Roles + +| Role | Responsibility | +|---|---| +| **Incident Lead** | First maintainer to triage the report. Owns the incident until resolution. | +| **Patch Owner** | Writes and tests the fix (may be the same person as Incident Lead). | +| **Release Manager** | Cuts the point release following [RELEASING.md](../RELEASING.md). | +| **Communications Owner** | Drafts the GitHub Security Advisory, announces on Mastodon, notifies distros. | +| **Tidelift Contact** | For reports that arrive via Tidelift, coordinate through the Tidelift security portal. | + +For the typical small maintainer team, one person may fill multiple roles. Assign roles +explicitly at the start of each incident to avoid gaps. + +--- + +## 4. Severity Classification + +Use the [CVSS v3.1](https://www.first.org/cvss/v3.1/specification-document) base score as +a guide, mapped to the following levels: + +| Severity | CVSS | Definition | Target Response SLA | +|---|---|---|---| +| **Critical** | 9.0 – 10.0 | Remote code execution, arbitrary write, or complete integrity/confidentiality loss achievable by opening a crafted image | 48 hours to patch; embargoed release where possible | +| **High** | 7.0 – 8.9 | Heap/stack buffer overflow, use-after-free, or significant information disclosure | 7 days to patch | +| **Medium** | 4.0 – 6.9 | Denial of service via crafted image, out-of-bounds read, limited info disclosure | Next scheduled quarterly release, or earlier point release if needed | +| **Low** | 0.1 – 3.9 | Minor information disclosure, unlikely to be exploitable in practice | Next quarterly release | + +Supply-chain and CI/CD incidents are always treated as **Critical** regardless of CVSS. + +--- + +## 5. Detection Sources + +Vulnerabilities and incidents may be reported or discovered through: + +1. **GitHub private security advisory** — preferred channel; see [SECURITY.md](SECURITY.md) +2. **Tidelift security contact** — +3. **Direct maintainer contact** — DM on Mastodon or email +4. **External researcher / coordinated disclosure** — e.g. Google Project Zero, vendor PSIRT +5. **Automated scanning** — Dependabot, GitHub code-scanning (CodeQL), CI fuzzing +6. **Distro security teams** — Debian, Red Hat, Ubuntu, Alpine may report upstream +7. **User bug report** — public issue (reassess if it has security implications before it stays public) + +--- + +## 6. Response Process + +### 6.1 Triage (all severities) + +1. **Acknowledge receipt** to the reporter within **72 hours** using the template in + [Appendix A](#appendix-a-communication-templates). Ask the reporter: + - How they would like to be credited (name, handle, or anonymous) + - Whether they intend to publish their own advisory, and if so, their preferred timeline + - Thank them explicitly — reporters do the project a favour by disclosing privately. +2. Reproduce the issue. If the report is invalid, close it and notify the reporter. +3. Assign a severity level (Section 3) and an Incident Lead. +4. If the GitHub Security Advisory was not created by the reporter, create one now and keep + it **private** until the fix is released. Add the reporter as a collaborator if they wish + to be involved. +5. **Request a CVE** through the GitHub Security Advisory workflow (GitHub is a CVE + Numbering Authority — no separate MITRE form required). The CVE is reserved privately + and published automatically when the advisory goes public. +6. Notify Tidelift if the severity is High or Critical. +7. **Escalation** — Escalate beyond the core maintainer team if any of the following apply: + - The vulnerability is being actively exploited in the wild → notify [GitHub Security](mailto:security@github.com) and the [Python Security Response Team](https://www.python.org/news/security/) + - The fix requires changes to CPython or a dependency outside Pillow's control → contact the relevant upstream immediately + - A legal concern arises (e.g. GDPR-reportable data exposure) → contact the project's legal/fiscal sponsor + - The Incident Lead is unreachable for > 24 hours on a Critical issue → any other maintainer may assume the role + +### 6.2 Fix Development + +1. Develop the fix in a **private fork** or directly in the private security advisory + workspace on GitHub. Do **not** push to a public branch before the embargo lifts. +2. Write a regression test that fails before the fix and passes after. +3. Run the full test suite locally across all supported Python versions: + ```bash + make release-test + ``` +4. Review the patch with at least one other maintainer. + +### 6.3 Standard (Non-Embargoed) Release + +For Medium and Low severity, or when no distro pre-notification is needed: + +1. Merge the fix to `main`, then cherry-pick to all affected release branches + (see [RELEASING.md — Point release](../RELEASING.md)). +2. Amend commit messages to include the CVE identifier. +3. Tag and push; the GitHub Actions "Wheels" workflow will build and upload to PyPI. +4. Publish the GitHub Security Advisory (this simultaneously publishes the CVE). +5. Announce on [Mastodon](https://fosstodon.org/@pillow). + +### 6.4 Embargoed Release + +For Critical and High severity where distro pre-notification improves user safety: + +1. Prepare patches against all affected release branches and test locally. +2. Agree on an **embargo date** with the reporter (typically 7–14 days out, up to 90 days for + complex issues). +3. Privately send the patch to distros via the + [linux-distros](https://oss-security.openwall.org/wiki/mailing-lists/distros) mailing list + or directly to individual distro security teams. +4. On the embargo date: + - Amend commit messages with the CVE identifier. + - Tag and push all affected release branches (see [RELEASING.md — Embargoed release](../RELEASING.md)). + - Confirm the "Wheels" workflow has passed and wheels are live on PyPI. + - Publish the GitHub Security Advisory. + - Announce on [Mastodon](https://fosstodon.org/@pillow). + +### 6.5 Rollback Procedures + +If a security patch introduces a critical regression after release: + +1. **Yank the release immediately** via the PyPI web interface: + [https://pypi.org/manage/project/pillow/release/\/](https://pypi.org/manage/project/pillow/) + (navigate to the release, click **"Yank"**). + Yanked releases remain downloadable by pinned users but are excluded from `pip install` + resolution, giving time to fix without leaving users unpatched. +2. Post a public notice in the GitHub release and on Mastodon explaining the regression and + that the release has been yanked. +3. If the previous (vulnerable) version was also yanked, **un-yank it temporarily** so users + have a functional fallback while the corrected release is prepared. +4. Prepare a corrected point release (incrementing the patch version), repeating §6.2–§6.3. +5. Document the regression in the post-incident review (§9). + +### 6.6 Supply-Chain / Infrastructure Compromise + +1. **Immediately** revoke any potentially compromised credentials: + - PyPI API tokens (regenerate and update in GitHub secrets) + - GitHub personal access tokens and OAuth apps + - Codecov or other CI service tokens +2. Audit recent commits and releases for tampering: + - Verify release tags against known-good SHAs + - Re-inspect any wheel published since the potential compromise window +3. If a PyPI release is suspected to be tampered: yank it immediately via + [https://pypi.org/manage/project/pillow/](https://pypi.org/manage/project/pillow/); + file a report with the [PyPI security team](mailto:security@pypi.org). +4. Notify GitHub Security if repository access or Actions secrets are involved. +5. Issue a public advisory describing the scope and any user action required. + +--- + +## 7. Communication + +### Internal (during embargo) +- Use the **private GitHub Security Advisory** thread for all coordination. +- Do not discuss details in public issues, PRs, or Gitter/IRC channels. + +### External (at or after disclosure) + +| Audience | Channel | Timing | +|---|---|---| +| General users | [GitHub Security Advisory](https://github.com/python-pillow/Pillow/security/advisories) | At release | +| PyPI ecosystem | CVE published via advisory | At release | +| Downstream distros | Direct email or linux-distros list | Before embargo date (embargoed) | +| Tidelift subscribers | Tidelift security portal | At release (or coordinated) | +| Community | [Mastodon @pillow](https://fosstodon.org/@pillow) | At release | + +**Advisory content should include:** +- CVE identifier and CVSS score +- Affected Pillow versions +- Fixed version(s) +- Nature of the vulnerability (without full exploit details if still fresh) +- Credit to the reporter (with their consent) +- Upgrade instructions (`pip install --upgrade Pillow`) + +--- + +## 8. Post-Incident Review + +Within **2 weeks** of a Critical or High severity fix being released: + +1. Hold a brief retrospective (async is fine for a distributed team). +2. Document the following metrics for the incident record: + + | Metric | Target | Actual | + |---|---|---| + | Time to acknowledge reporter | ≤ 72 hours | | + | Time to reproduce & assess severity | ≤ 5 days | | + | Time to develop & review fix | Varies by severity | | + | Time from report to public release | Critical ≤ 14 days; High ≤ 30 days | | + +3. Record: + - What went well + - What could be improved + - Root cause: what allowed the vulnerability to exist + - Whether any distro/downstream was impacted before the fix was available +4. File follow-up issues for any process improvements identified. +5. Update this document if the response process needs revision. + +--- + +## 9. Dependency Map + +Understanding what Pillow depends on (upstream) and what depends on Pillow (downstream) +is essential for scoping impact and coordinating notifications during an incident. + +### 9.1 Upstream Dependencies + +#### Bundled C libraries (shipped in official wheels) + +These libraries are compiled into Pillow's binary wheels. A CVE in any of them may +require a Pillow point release even if Pillow's own code is unchanged. + +| Library | Purpose | Security advisory tracker | +|---|---|---| +| [libjpeg-turbo](https://libjpeg-turbo.org/) | JPEG encode/decode | [GitHub](https://github.com/libjpeg-turbo/libjpeg-turbo/security) | +| [libpng](http://www.libpng.org/pub/png/libpng.html) | PNG encode/decode | [SourceForge](https://sourceforge.net/p/libpng/bugs/) | +| [libtiff](https://libtiff.gitlab.io/libtiff/) | TIFF encode/decode | [GitLab](https://gitlab.com/libtiff/libtiff/-/issues) | +| [libwebp](https://chromium.googlesource.com/webm/libwebp) | WebP encode/decode | [Chromium tracker](https://bugs.chromium.org/p/webm/) | +| [libavif](https://github.com/AOMediaCodec/libavif) | AVIF encode/decode | [GitHub](https://github.com/AOMediaCodec/libavif/security) | +| [aom](https://aomedia.googlesource.com/aom/) | AV1 codec (AVIF) | [Chromium tracker](https://bugs.chromium.org/p/aomedia/) | +| [dav1d](https://code.videolan.org/videolan/dav1d) | AV1 decode (AVIF) | [VideoLAN](https://security.videolan.org/) | +| [openjpeg](https://www.openjpeg.org/) | JPEG 2000 encode/decode | [GitHub](https://github.com/uclouvain/openjpeg/security) | +| [freetype2](https://freetype.org/) | Font rendering | [GitLab](https://gitlab.freedesktop.org/freetype/freetype/-/issues) | +| [lcms2](https://www.littlecms.com/) | ICC color management | [GitHub](https://github.com/mm2/Little-CMS) | +| [harfbuzz](https://harfbuzz.github.io/) | Text shaping (via raqm) | [GitHub](https://github.com/harfbuzz/harfbuzz/security) | +| [raqm](https://github.com/HOST-Oman/libraqm) | Complex text layout | [GitHub](https://github.com/HOST-Oman/libraqm) | +| [fribidi](https://github.com/fribidi/fribidi) | Unicode bidi (via raqm) | [GitHub](https://github.com/fribidi/fribidi) | +| [zlib](https://zlib.net/) | Deflate compression | [zlib.net](https://zlib.net/) | +| [liblzma / xz-utils](https://tukaani.org/xz/) | XZ/LZMA compression | [GitHub](https://github.com/tukaani-project/xz) | +| [bzip2](https://sourceware.org/bzip2/) | BZ2 compression | [Sourceware](https://sourceware.org/bzip2/) | +| [zstd](https://github.com/facebook/zstd) | Zstandard compression | [GitHub](https://github.com/facebook/zstd/security) | +| [brotli](https://github.com/google/brotli) | Brotli compression | [GitHub](https://github.com/google/brotli) | +| [libyuv](https://chromium.googlesource.com/libyuv/libyuv/) | YUV conversion | [Chromium tracker](https://bugs.chromium.org/p/libyuv/) | + +#### Python-level dependencies + +| Package | Required? | Purpose | +|---|---|---| +| `pybind11` | Build-time only | C++ ↔ Python bindings | +| `olefile` | Optional (`fpx`, `mic` extras) | OLE2 container parsing (FPX, MIC formats) | +| `defusedxml` | Optional (`xmp` extra) | Safe XML parsing for XMP metadata | + +### 9.2 Downstream Dependencies + +A vulnerability in Pillow can have wide impact. Notify or consider the blast radius of +these downstream consumers when assessing severity and planning communications. + +#### Linux distribution packages + +| Distribution | Package name | Security contact | +|---|---|---| +| Debian / Ubuntu | `python3-pil` | [Debian Security](https://www.debian.org/security/) / [Ubuntu Security](https://ubuntu.com/security) | +| Fedora / RHEL / CentOS | `python3-pillow` | [Red Hat Security](https://access.redhat.com/security/) | +| Alpine Linux | `py3-pillow` | [Alpine security](https://security.alpinelinux.org/) | +| Arch Linux | `python-pillow` | [Arch security tracker](https://security.archlinux.org/) | +| Homebrew (macOS) | `pillow` | [Homebrew maintainers](https://github.com/Homebrew/homebrew-core) | +| conda-forge | `pillow` | [conda-forge](https://github.com/conda-forge/pillow-feedstock) | + +#### Major Python ecosystem consumers + +These are high-profile projects known to depend on Pillow; a critical vulnerability may +warrant proactive notification. + +| Project | Usage | +|---|---| +| [matplotlib](https://matplotlib.org/) | Image I/O for plots | +| [scikit-image](https://scikit-image.org/) | Image processing | +| [torchvision](https://github.com/pytorch/vision) (PyTorch) | Dataset loading, transforms | +| [Keras / TensorFlow](https://keras.io/) | Image preprocessing utilities | +| [Django](https://www.djangoproject.com/) | `ImageField` validation and thumbnail generation | +| [Wagtail](https://wagtail.org/) | CMS image renditions | +| [Plone](https://plone.org/) | CMS image handling | +| [Jupyter / IPython](https://jupyter.org/) | Inline image display | +| [ReportLab](https://www.reportlab.com/) | PDF image embedding | +| [Wand](https://docs.wand-py.org/) | Sometimes used alongside Pillow | +| [Tidelift subscribers](https://tidelift.com/) | Enterprise consumers (coordinated via Tidelift) | + +#### Pillow ecosystem plugins + +Third-party plugins extend Pillow and are distributed separately on PyPI. Their +maintainers should be notified for Critical/High issues that affect the plugin API +or the formats they decode. See the +[full plugin list](https://pillow.readthedocs.io/en/stable/handbook/third-party-plugins.html). + +### 9.3 Responding to an Upstream Vulnerability + +When a CVE is published for a bundled C library: + +1. Assess whether the vulnerable code path is reachable through Pillow's API. +2. If reachable, treat as a Pillow vulnerability and follow Section 5. +3. Update the bundled library version in the wheel build scripts and rebuild wheels. +4. Reference the upstream CVE in Pillow's release notes and GitHub Security Advisory. +5. If not reachable, document the rationale in a public issue so downstream distributors + can make informed decisions about patching their system packages. + +--- + +## 10. References + +- [Security Policy](SECURITY.md) +- [Release Checklist](../RELEASING.md) +- [Contributing Guide](CONTRIBUTING.md) +- [Tidelift Security Contact](https://tidelift.com/security) +- [GitHub: Privately reporting a security vulnerability](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing/privately-reporting-a-security-vulnerability) +- [GitHub as a CVE Numbering Authority (CNA)](https://docs.github.com/en/code-security/security-advisories/working-with-repository-security-advisories/about-github-security-advisories-for-repositories#cve-identification-numbers) +- [FIRST CVSS v3.1 Calculator](https://www.first.org/cvss/calculator/3.1) +- [linux-distros mailing list](https://oss-security.openwall.org/wiki/mailing-lists/distros) +- [OpenSSF CVD Guide](https://github.com/ossf/oss-vulnerability-guide) *(basis for this plan)* + +--- + +## Appendix A: Communication Templates + +### A.1 Reporter Acknowledgment + +> Subject: Re: [Security] \ +> +> Hi \, +> +> Thank you for taking the time to report this — we genuinely appreciate it. +> +> We have received your report and will assess it within the next few days. We will keep +> you updated on our progress. +> +> A few quick questions so we can handle this well: +> - How would you like to be credited in the advisory? (name, handle, organisation, or anonymous) +> - Do you plan to publish your own write-up or advisory? If so, is there a disclosure date +> that works for you? +> +> We aim to treat all vulnerability reports in line with coordinated disclosure principles. +> If you have any questions or concerns at any point, please reply to this thread. +> +> Thanks again, +> The Pillow maintainers + +### A.2 Embargoed Distro Notification + +> Subject: [EMBARGOED] Pillow security issue — \ — disclosure \ +> +> This is an embargoed notification of a vulnerability in Pillow. Please keep this +> information confidential until the disclosure date listed below. +> +> **CVE:** \ +> **Affected versions:** \ +> **Fixed version:** \ +> **Severity:** \ (CVSS \: \) +> **Reporter:** \ +> **Public disclosure date:** \ +> +> **Summary:** +> \ +> +> **Proof of concept:** +> \ +> +> **Remediation:** +> Upgrade to Pillow \. No known workaround. +> +> Please do not share this information, issue public patches, or make user communications +> before the disclosure date. We will notify this list immediately if the date changes. +> +> — The Pillow maintainers + +### A.3 Public Disclosure Advisory + +*(Published as a GitHub Security Advisory; the CVE and date are included automatically.)* + +> **Summary:** \ +> +> **CVE:** \ +> **Affected versions:** Pillow \< \ +> **Fixed version:** \ +> **Severity:** \ (CVSS \) +> **Reporter:** \ +> +> **Details:** +> \ +> +> **Remediation:** +> ``` +> pip install --upgrade Pillow +> ``` +> +> **Timeline:** +> - Reported: \ +> - Fixed: \ +> - Disclosed: \ From 4d63d0b3a6c5deccce7f33ecf1e6c3d74ee9d8a5 Mon Sep 17 00:00:00 2001 From: Jeffrey 'Alex' Clark Date: Thu, 9 Apr 2026 12:47:50 -0400 Subject: [PATCH 02/20] Fix links --- .github/INCIDENT_RESPONSE.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/INCIDENT_RESPONSE.md b/.github/INCIDENT_RESPONSE.md index 03371c4f3b7..65b1f1b7d62 100644 --- a/.github/INCIDENT_RESPONSE.md +++ b/.github/INCIDENT_RESPONSE.md @@ -174,7 +174,7 @@ For Critical and High severity where distro pre-notification improves user safet If a security patch introduces a critical regression after release: 1. **Yank the release immediately** via the PyPI web interface: - [https://pypi.org/manage/project/pillow/release/\/](https://pypi.org/manage/project/pillow/) + [https://pypi.org/manage/project/pillow/](https://pypi.org/manage/project/pillow/) (navigate to the release, click **"Yank"**). Yanked releases remain downloadable by pinned users but are excluded from `pip install` resolution, giving time to fix without leaving users unpatched. @@ -272,7 +272,7 @@ require a Pillow point release even if Pillow's own code is unchanged. | [libwebp](https://chromium.googlesource.com/webm/libwebp) | WebP encode/decode | [Chromium tracker](https://bugs.chromium.org/p/webm/) | | [libavif](https://github.com/AOMediaCodec/libavif) | AVIF encode/decode | [GitHub](https://github.com/AOMediaCodec/libavif/security) | | [aom](https://aomedia.googlesource.com/aom/) | AV1 codec (AVIF) | [Chromium tracker](https://bugs.chromium.org/p/aomedia/) | -| [dav1d](https://code.videolan.org/videolan/dav1d) | AV1 decode (AVIF) | [VideoLAN](https://security.videolan.org/) | +| [dav1d](https://code.videolan.org/videolan/dav1d) | AV1 decode (AVIF) | [VideoLAN Security](https://www.videolan.org/security/) | | [openjpeg](https://www.openjpeg.org/) | JPEG 2000 encode/decode | [GitHub](https://github.com/uclouvain/openjpeg/security) | | [freetype2](https://freetype.org/) | Font rendering | [GitLab](https://gitlab.freedesktop.org/freetype/freetype/-/issues) | | [lcms2](https://www.littlecms.com/) | ICC color management | [GitHub](https://github.com/mm2/Little-CMS) | @@ -281,7 +281,7 @@ require a Pillow point release even if Pillow's own code is unchanged. | [fribidi](https://github.com/fribidi/fribidi) | Unicode bidi (via raqm) | [GitHub](https://github.com/fribidi/fribidi) | | [zlib](https://zlib.net/) | Deflate compression | [zlib.net](https://zlib.net/) | | [liblzma / xz-utils](https://tukaani.org/xz/) | XZ/LZMA compression | [GitHub](https://github.com/tukaani-project/xz) | -| [bzip2](https://sourceware.org/bzip2/) | BZ2 compression | [Sourceware](https://sourceware.org/bzip2/) | +| [bzip2](https://gitlab.com/bzip2/bzip2) | BZ2 compression | [GitLab](https://gitlab.com/bzip2/bzip2/-/issues) | | [zstd](https://github.com/facebook/zstd) | Zstandard compression | [GitHub](https://github.com/facebook/zstd/security) | | [brotli](https://github.com/google/brotli) | Brotli compression | [GitHub](https://github.com/google/brotli) | | [libyuv](https://chromium.googlesource.com/libyuv/libyuv/) | YUV conversion | [Chromium tracker](https://bugs.chromium.org/p/libyuv/) | @@ -356,7 +356,7 @@ When a CVE is published for a bundled C library: - [Contributing Guide](CONTRIBUTING.md) - [Tidelift Security Contact](https://tidelift.com/security) - [GitHub: Privately reporting a security vulnerability](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing/privately-reporting-a-security-vulnerability) -- [GitHub as a CVE Numbering Authority (CNA)](https://docs.github.com/en/code-security/security-advisories/working-with-repository-security-advisories/about-github-security-advisories-for-repositories#cve-identification-numbers) +- [GitHub as a CVE Numbering Authority (CNA)](https://docs.github.com/en/code-security/security-advisories/working-with-repository-security-advisories/about-repository-security-advisories) - [FIRST CVSS v3.1 Calculator](https://www.first.org/cvss/calculator/3.1) - [linux-distros mailing list](https://oss-security.openwall.org/wiki/mailing-lists/distros) - [OpenSSF CVD Guide](https://github.com/ossf/oss-vulnerability-guide) *(basis for this plan)* From cdaa1bf9ef0faca5ddf2f2e7d8742678552a90d1 Mon Sep 17 00:00:00 2001 From: Jeffrey 'Alex' Clark Date: Thu, 9 Apr 2026 12:57:16 -0400 Subject: [PATCH 03/20] Add sections from Bootstrap example At the risk of making this document larger, add in sections in Bootstrap IRP but not ours. - https://github.com/twbs/bootstrap/blob/main/.github/INCIDENT_RESPONSE.md --- .github/INCIDENT_RESPONSE.md | 75 +++++++++++++++++++++++++++--------- 1 file changed, 57 insertions(+), 18 deletions(-) diff --git a/.github/INCIDENT_RESPONSE.md b/.github/INCIDENT_RESPONSE.md index 65b1f1b7d62..6fdbfff2e22 100644 --- a/.github/INCIDENT_RESPONSE.md +++ b/.github/INCIDENT_RESPONSE.md @@ -61,7 +61,21 @@ This plan covers: --- -## 3. Roles +## 3. Definitions + +| Term | Meaning | +|---|---| +| **Incident** | Any event that compromises or threatens the confidentiality, integrity, or availability of Pillow's code, release artifacts, or infrastructure. | +| **Vulnerability** | A security flaw in Pillow or a bundled library that can be exploited by a crafted image or API call. | +| **Incident Lead** | The maintainer who owns coordination of the response from triage to closure. | +| **Embargo** | A period during which fix details are kept private to allow coordinated patching before public disclosure. | +| **Yank** | A PyPI action that keeps a release downloadable by pinned users but removes it from default `pip install` resolution. | +| **CVE** | Common Vulnerabilities and Exposures — a public identifier assigned to a specific vulnerability. | +| **CNA** | CVE Numbering Authority — GitHub is a CNA and can assign CVEs directly through the advisory workflow. | + +--- + +## 4. Roles | Role | Responsibility | |---|---| @@ -76,7 +90,7 @@ explicitly at the start of each incident to avoid gaps. --- -## 4. Severity Classification +## 5. Severity Classification Use the [CVSS v3.1](https://www.first.org/cvss/v3.1/specification-document) base score as a guide, mapped to the following levels: @@ -90,9 +104,11 @@ a guide, mapped to the following levels: Supply-chain and CI/CD incidents are always treated as **Critical** regardless of CVSS. +> **Note:** These are good-faith targets for a small volunteer maintainer team, not contractual SLAs. Public safety and transparency will always be prioritised, even when timing varies. + --- -## 5. Detection Sources +## 6. Detection Sources Vulnerabilities and incidents may be reported or discovered through: @@ -106,9 +122,9 @@ Vulnerabilities and incidents may be reported or discovered through: --- -## 6. Response Process +## 7. Response Process -### 6.1 Triage (all severities) +### 7.1 Triage (all severities) 1. **Acknowledge receipt** to the reporter within **72 hours** using the template in [Appendix A](#appendix-a-communication-templates). Ask the reporter: @@ -130,7 +146,7 @@ Vulnerabilities and incidents may be reported or discovered through: - A legal concern arises (e.g. GDPR-reportable data exposure) → contact the project's legal/fiscal sponsor - The Incident Lead is unreachable for > 24 hours on a Critical issue → any other maintainer may assume the role -### 6.2 Fix Development +### 7.2 Fix Development 1. Develop the fix in a **private fork** or directly in the private security advisory workspace on GitHub. Do **not** push to a public branch before the embargo lifts. @@ -141,7 +157,7 @@ Vulnerabilities and incidents may be reported or discovered through: ``` 4. Review the patch with at least one other maintainer. -### 6.3 Standard (Non-Embargoed) Release +### 7.3 Standard (Non-Embargoed) Release For Medium and Low severity, or when no distro pre-notification is needed: @@ -152,7 +168,7 @@ For Medium and Low severity, or when no distro pre-notification is needed: 4. Publish the GitHub Security Advisory (this simultaneously publishes the CVE). 5. Announce on [Mastodon](https://fosstodon.org/@pillow). -### 6.4 Embargoed Release +### 7.4 Embargoed Release For Critical and High severity where distro pre-notification improves user safety: @@ -169,7 +185,7 @@ For Critical and High severity where distro pre-notification improves user safet - Publish the GitHub Security Advisory. - Announce on [Mastodon](https://fosstodon.org/@pillow). -### 6.5 Rollback Procedures +### 7.5 Rollback Procedures If a security patch introduces a critical regression after release: @@ -182,10 +198,10 @@ If a security patch introduces a critical regression after release: that the release has been yanked. 3. If the previous (vulnerable) version was also yanked, **un-yank it temporarily** so users have a functional fallback while the corrected release is prepared. -4. Prepare a corrected point release (incrementing the patch version), repeating §6.2–§6.3. +4. Prepare a corrected point release (incrementing the patch version), repeating §7.2–§7.3. 5. Document the regression in the post-incident review (§9). -### 6.6 Supply-Chain / Infrastructure Compromise +### 7.6 Supply-Chain / Infrastructure Compromise 1. **Immediately** revoke any potentially compromised credentials: - PyPI API tokens (regenerate and update in GitHub secrets) @@ -200,9 +216,19 @@ If a security patch introduces a critical regression after release: 4. Notify GitHub Security if repository access or Actions secrets are involved. 5. Issue a public advisory describing the scope and any user action required. +### 7.7 Recovery + +After the fix is released and the advisory is public: + +1. Verify that the patched wheels are live on PyPI and passing CI across all supported platforms. +2. Confirm any yanked releases are handled correctly (re-yank if un-yanked as a fallback during rollback). +3. Resume normal development operations on `main`. +4. Monitor the GitHub issue tracker and Mastodon for user reports of residual problems for at least **72 hours** post-release. +5. Close the private GitHub Security Advisory once recovery is confirmed. + --- -## 7. Communication +## 8. Communication ### Internal (during embargo) - Use the **private GitHub Security Advisory** thread for all coordination. @@ -228,7 +254,7 @@ If a security patch introduces a critical regression after release: --- -## 8. Post-Incident Review +## 9. Post-Incident Review Within **2 weeks** of a Critical or High severity fix being released: @@ -252,12 +278,12 @@ Within **2 weeks** of a Critical or High severity fix being released: --- -## 9. Dependency Map +## 10. Dependency Map Understanding what Pillow depends on (upstream) and what depends on Pillow (downstream) is essential for scoping impact and coordinating notifications during an incident. -### 9.1 Upstream Dependencies +### 10.1 Upstream Dependencies #### Bundled C libraries (shipped in official wheels) @@ -294,7 +320,7 @@ require a Pillow point release even if Pillow's own code is unchanged. | `olefile` | Optional (`fpx`, `mic` extras) | OLE2 container parsing (FPX, MIC formats) | | `defusedxml` | Optional (`xmp` extra) | Safe XML parsing for XMP metadata | -### 9.2 Downstream Dependencies +### 10.2 Downstream Dependencies A vulnerability in Pillow can have wide impact. Notify or consider the blast radius of these downstream consumers when assessing severity and planning communications. @@ -336,7 +362,7 @@ maintainers should be notified for Critical/High issues that affect the plugin A or the formats they decode. See the [full plugin list](https://pillow.readthedocs.io/en/stable/handbook/third-party-plugins.html). -### 9.3 Responding to an Upstream Vulnerability +### 10.3 Responding to an Upstream Vulnerability When a CVE is published for a bundled C library: @@ -349,7 +375,20 @@ When a CVE is published for a bundled C library: --- -## 10. References +## 11. Plan Maintenance + +This document is a living record. It should be kept current so it is useful when an +incident actually occurs. + +- **Annual review** — revisit during the §1.3 readiness review each January. +- **Post-incident update** — if the response process revealed gaps or needed improvisation, + update this document before the post-incident review is closed (§9). +- **Ownership** — changes are approved by the Core Team and recorded in Git history. + Substantive changes should be noted in the PR description so they are easy to find later. + +--- + +## 12. References - [Security Policy](SECURITY.md) - [Release Checklist](../RELEASING.md) From 64ed4710b9282d4547ee62883e3f496f2de31fb0 Mon Sep 17 00:00:00 2001 From: Jeffrey 'Alex' Clark Date: Thu, 9 Apr 2026 16:59:41 -0400 Subject: [PATCH 04/20] Fix version support matrix to reflect main-only security policy Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/INCIDENT_RESPONSE.md | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/.github/INCIDENT_RESPONSE.md b/.github/INCIDENT_RESPONSE.md index 6fdbfff2e22..921dfedd85b 100644 --- a/.github/INCIDENT_RESPONSE.md +++ b/.github/INCIDENT_RESPONSE.md @@ -12,17 +12,18 @@ Maintaining readiness before an incident occurs reduces response time and errors ### 1.1 Version Support Matrix -Only the following branches receive security fixes. Reporters should verify their affected -version before filing; maintainers should cherry-pick fixes only to supported branches. +Security fixes are applied to the **latest stable release only**. Users on older versions +are expected to upgrade. This is consistent with Pillow's quarterly release cadence and +is not currently documented elsewhere — reporters should assume only the latest release +will receive a patch. -| Branch | Status | Notes | -|---|---|---| -| `main` | ✅ Active development | Always patched | -| Latest stable (e.g. `11.x`) | ✅ Security fixes | Current quarterly release series | -| Previous stable (e.g. `10.x`) | ⚠️ Critical only | One release series back; Critical CVEs only | -| Older branches | ❌ End of life | No security support; users must upgrade | +| Branch | Status | +|---|---| +| `main` / latest stable | ✅ Security fixes applied | +| All older releases | ❌ No security support — please upgrade | -> Update this table with each quarterly release. +> If backport support for older releases is ever added, update this table and document it +> in [SECURITY.md](SECURITY.md). ### 1.2 Team Readiness From 4a74a20b86b9a6c4836b54f336356accfdf53278 Mon Sep 17 00:00:00 2001 From: Jeffrey 'Alex' Clark Date: Thu, 9 Apr 2026 17:02:24 -0400 Subject: [PATCH 05/20] Update Readiness Review: quarterly cadence, trim checklist Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/INCIDENT_RESPONSE.md | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/.github/INCIDENT_RESPONSE.md b/.github/INCIDENT_RESPONSE.md index 921dfedd85b..8e35754aac7 100644 --- a/.github/INCIDENT_RESPONSE.md +++ b/.github/INCIDENT_RESPONSE.md @@ -27,24 +27,15 @@ will receive a patch. ### 1.2 Team Readiness -- Maintain a private list of current maintainer contact details (GitHub handles, email, - Mastodon) in a location accessible to all maintainers (e.g. a pinned private team - discussion or the Tidelift maintainer portal). -- Ensure at least two maintainers have admin access to: - - The GitHub repository (to manage Security Advisories) - - The [PyPI Pillow project](https://pypi.org/project/Pillow/) (to yank releases) - - The Tidelift maintainer portal -- Rotate and audit PyPI API tokens and GitHub Actions secrets at least once per year, - and immediately after any maintainer leaves the project. +The four members of the Pillow core team are in regular contact and share collective +responsibility for incident response. Any core team member may act as Incident Lead. +Contact details are known to all team members. -### 1.3 Annual Readiness Review +### 1.3 Readiness Review -Once per year (suggested: at the January quarterly release), maintainers should: +At each quarterly release, maintainers should: 1. Re-read this document and update any stale content (version table, contacts, tooling). -2. Verify the GitHub private security advisory flow still works (open and close a test advisory). -3. Confirm PyPI yank access is functional. -4. Review Dependabot and CodeQL alert settings are enabled on the repository. --- @@ -381,7 +372,7 @@ When a CVE is published for a bundled C library: This document is a living record. It should be kept current so it is useful when an incident actually occurs. -- **Annual review** — revisit during the §1.3 readiness review each January. +- **Quarterly review** — revisit during the §1.3 readiness review at each quarterly release. - **Post-incident update** — if the response process revealed gaps or needed improvisation, update this document before the post-incident review is closed (§9). - **Ownership** — changes are approved by the Core Team and recorded in Git history. From 3aa076129fa66eefa213c9708779ce36c832ed93 Mon Sep 17 00:00:00 2001 From: Jeffrey 'Alex' Clark Date: Thu, 9 Apr 2026 17:25:32 -0400 Subject: [PATCH 06/20] Remove backport comment from version support matrix Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/INCIDENT_RESPONSE.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/INCIDENT_RESPONSE.md b/.github/INCIDENT_RESPONSE.md index 8e35754aac7..0662a3a31bc 100644 --- a/.github/INCIDENT_RESPONSE.md +++ b/.github/INCIDENT_RESPONSE.md @@ -22,9 +22,6 @@ will receive a patch. | `main` / latest stable | ✅ Security fixes applied | | All older releases | ❌ No security support — please upgrade | -> If backport support for older releases is ever added, update this table and document it -> in [SECURITY.md](SECURITY.md). - ### 1.2 Team Readiness The four members of the Pillow core team are in regular contact and share collective From c2ac2da31ccabc8d9c49f7bad1d36e9578b97e44 Mon Sep 17 00:00:00 2001 From: Jeffrey 'Alex' Clark Date: Thu, 9 Apr 2026 17:28:42 -0400 Subject: [PATCH 07/20] Inline Readiness Review procedure as prose Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/INCIDENT_RESPONSE.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/INCIDENT_RESPONSE.md b/.github/INCIDENT_RESPONSE.md index 0662a3a31bc..186d054c6ee 100644 --- a/.github/INCIDENT_RESPONSE.md +++ b/.github/INCIDENT_RESPONSE.md @@ -30,9 +30,7 @@ Contact details are known to all team members. ### 1.3 Readiness Review -At each quarterly release, maintainers should: - -1. Re-read this document and update any stale content (version table, contacts, tooling). +At each quarterly release, maintainers should re-read this document and update any stale content. --- From ad582c1a8eac0c609ca84fea80d938a58dfe0597 Mon Sep 17 00:00:00 2001 From: Jeffrey 'Alex' Clark Date: Thu, 9 Apr 2026 17:38:34 -0400 Subject: [PATCH 08/20] Simplify Roles section note Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/INCIDENT_RESPONSE.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/INCIDENT_RESPONSE.md b/.github/INCIDENT_RESPONSE.md index 186d054c6ee..c6898969aea 100644 --- a/.github/INCIDENT_RESPONSE.md +++ b/.github/INCIDENT_RESPONSE.md @@ -72,8 +72,7 @@ This plan covers: | **Communications Owner** | Drafts the GitHub Security Advisory, announces on Mastodon, notifies distros. | | **Tidelift Contact** | For reports that arrive via Tidelift, coordinate through the Tidelift security portal. | -For the typical small maintainer team, one person may fill multiple roles. Assign roles -explicitly at the start of each incident to avoid gaps. +One person may fill multiple roles. --- From e0f9e2b98ef9d4cf278117160f4aa86f7b4e44ba Mon Sep 17 00:00:00 2001 From: Jeffrey 'Alex' Clark Date: Thu, 9 Apr 2026 17:46:58 -0400 Subject: [PATCH 09/20] Fix severity classification cross-reference, remove incident lead assignment step Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/INCIDENT_RESPONSE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/INCIDENT_RESPONSE.md b/.github/INCIDENT_RESPONSE.md index c6898969aea..9cb6ba9db14 100644 --- a/.github/INCIDENT_RESPONSE.md +++ b/.github/INCIDENT_RESPONSE.md @@ -118,7 +118,7 @@ Vulnerabilities and incidents may be reported or discovered through: - Whether they intend to publish their own advisory, and if so, their preferred timeline - Thank them explicitly — reporters do the project a favour by disclosing privately. 2. Reproduce the issue. If the report is invalid, close it and notify the reporter. -3. Assign a severity level (Section 3) and an Incident Lead. +3. Assign a severity level ([§5 Severity Classification](#5-severity-classification)). 4. If the GitHub Security Advisory was not created by the reporter, create one now and keep it **private** until the fix is released. Add the reporter as a collaborator if they wish to be involved. From 68be7f30ff2872a474c4de9484f44061733eaf78 Mon Sep 17 00:00:00 2001 From: Jeffrey 'Alex' Clark Date: Thu, 9 Apr 2026 17:50:45 -0400 Subject: [PATCH 10/20] Remove Tidelift notification step from triage Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/INCIDENT_RESPONSE.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/INCIDENT_RESPONSE.md b/.github/INCIDENT_RESPONSE.md index 9cb6ba9db14..af4217876fc 100644 --- a/.github/INCIDENT_RESPONSE.md +++ b/.github/INCIDENT_RESPONSE.md @@ -125,8 +125,7 @@ Vulnerabilities and incidents may be reported or discovered through: 5. **Request a CVE** through the GitHub Security Advisory workflow (GitHub is a CVE Numbering Authority — no separate MITRE form required). The CVE is reserved privately and published automatically when the advisory goes public. -6. Notify Tidelift if the severity is High or Critical. -7. **Escalation** — Escalate beyond the core maintainer team if any of the following apply: +6. **Escalation** — Escalate beyond the core maintainer team if any of the following apply: - The vulnerability is being actively exploited in the wild → notify [GitHub Security](mailto:security@github.com) and the [Python Security Response Team](https://www.python.org/news/security/) - The fix requires changes to CPython or a dependency outside Pillow's control → contact the relevant upstream immediately - A legal concern arises (e.g. GDPR-reportable data exposure) → contact the project's legal/fiscal sponsor From 3f90d5c4da6efc69641ecee639b1eba6dbb20bc7 Mon Sep 17 00:00:00 2001 From: Jeffrey 'Alex' Clark Date: Thu, 9 Apr 2026 17:53:04 -0400 Subject: [PATCH 11/20] =?UTF-8?q?Replace=20section=20sign=20(=C2=A7)=20wit?= =?UTF-8?q?h=20plain=20Section=20references?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/INCIDENT_RESPONSE.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/INCIDENT_RESPONSE.md b/.github/INCIDENT_RESPONSE.md index af4217876fc..5295a48db9c 100644 --- a/.github/INCIDENT_RESPONSE.md +++ b/.github/INCIDENT_RESPONSE.md @@ -118,7 +118,7 @@ Vulnerabilities and incidents may be reported or discovered through: - Whether they intend to publish their own advisory, and if so, their preferred timeline - Thank them explicitly — reporters do the project a favour by disclosing privately. 2. Reproduce the issue. If the report is invalid, close it and notify the reporter. -3. Assign a severity level ([§5 Severity Classification](#5-severity-classification)). +3. Assign a severity level ([Section 5: Severity Classification](#5-severity-classification)). 4. If the GitHub Security Advisory was not created by the reporter, create one now and keep it **private** until the fix is released. Add the reporter as a collaborator if they wish to be involved. @@ -183,8 +183,8 @@ If a security patch introduces a critical regression after release: that the release has been yanked. 3. If the previous (vulnerable) version was also yanked, **un-yank it temporarily** so users have a functional fallback while the corrected release is prepared. -4. Prepare a corrected point release (incrementing the patch version), repeating §7.2–§7.3. -5. Document the regression in the post-incident review (§9). +4. Prepare a corrected point release (incrementing the patch version), repeating sections 7.2–7.3. +5. Document the regression in the post-incident review (Section 9). ### 7.6 Supply-Chain / Infrastructure Compromise @@ -365,9 +365,9 @@ When a CVE is published for a bundled C library: This document is a living record. It should be kept current so it is useful when an incident actually occurs. -- **Quarterly review** — revisit during the §1.3 readiness review at each quarterly release. +- **Quarterly review** — revisit during the Section 1.3 readiness review at each quarterly release. - **Post-incident update** — if the response process revealed gaps or needed improvisation, - update this document before the post-incident review is closed (§9). + update this document before the post-incident review is closed (Section 9). - **Ownership** — changes are approved by the Core Team and recorded in Git history. Substantive changes should be noted in the PR description so they are easy to find later. From 20af4ec89c6dd568f256864c4f5407595238e3b3 Mon Sep 17 00:00:00 2001 From: Jeffrey 'Alex' Clark Date: Thu, 9 Apr 2026 17:55:11 -0400 Subject: [PATCH 12/20] Change Critical/High SLA targets to best effort Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/INCIDENT_RESPONSE.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/INCIDENT_RESPONSE.md b/.github/INCIDENT_RESPONSE.md index 5295a48db9c..f8cabe88dd6 100644 --- a/.github/INCIDENT_RESPONSE.md +++ b/.github/INCIDENT_RESPONSE.md @@ -83,8 +83,8 @@ a guide, mapped to the following levels: | Severity | CVSS | Definition | Target Response SLA | |---|---|---|---| -| **Critical** | 9.0 – 10.0 | Remote code execution, arbitrary write, or complete integrity/confidentiality loss achievable by opening a crafted image | 48 hours to patch; embargoed release where possible | -| **High** | 7.0 – 8.9 | Heap/stack buffer overflow, use-after-free, or significant information disclosure | 7 days to patch | +| **Critical** | 9.0 – 10.0 | Remote code execution, arbitrary write, or complete integrity/confidentiality loss achievable by opening a crafted image | Best effort; embargoed release where possible | +| **High** | 7.0 – 8.9 | Heap/stack buffer overflow, use-after-free, or significant information disclosure | Best effort | | **Medium** | 4.0 – 6.9 | Denial of service via crafted image, out-of-bounds read, limited info disclosure | Next scheduled quarterly release, or earlier point release if needed | | **Low** | 0.1 – 3.9 | Minor information disclosure, unlikely to be exploitable in practice | Next quarterly release | From e74a89f70e419a4035428bc558e6a674ba53dab6 Mon Sep 17 00:00:00 2001 From: Jeffrey 'Alex' Clark Date: Thu, 9 Apr 2026 17:59:29 -0400 Subject: [PATCH 13/20] Trim version support matrix prose Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/INCIDENT_RESPONSE.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/INCIDENT_RESPONSE.md b/.github/INCIDENT_RESPONSE.md index f8cabe88dd6..4bcd22c692c 100644 --- a/.github/INCIDENT_RESPONSE.md +++ b/.github/INCIDENT_RESPONSE.md @@ -13,9 +13,7 @@ Maintaining readiness before an incident occurs reduces response time and errors ### 1.1 Version Support Matrix Security fixes are applied to the **latest stable release only**. Users on older versions -are expected to upgrade. This is consistent with Pillow's quarterly release cadence and -is not currently documented elsewhere — reporters should assume only the latest release -will receive a patch. +are expected to upgrade. Reporters should assume only the latest release will receive a patch. | Branch | Status | |---|---| From 00ff8636a27f6d25d4abb8ea52040356df77c8a1 Mon Sep 17 00:00:00 2001 From: Jeffrey 'Alex' Clark Date: Thu, 9 Apr 2026 18:01:08 -0400 Subject: [PATCH 14/20] Remove section 7.5 Rollback Procedures Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/INCIDENT_RESPONSE.md | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/.github/INCIDENT_RESPONSE.md b/.github/INCIDENT_RESPONSE.md index 4bcd22c692c..c879e4ed9ad 100644 --- a/.github/INCIDENT_RESPONSE.md +++ b/.github/INCIDENT_RESPONSE.md @@ -168,23 +168,7 @@ For Critical and High severity where distro pre-notification improves user safet - Publish the GitHub Security Advisory. - Announce on [Mastodon](https://fosstodon.org/@pillow). -### 7.5 Rollback Procedures - -If a security patch introduces a critical regression after release: - -1. **Yank the release immediately** via the PyPI web interface: - [https://pypi.org/manage/project/pillow/](https://pypi.org/manage/project/pillow/) - (navigate to the release, click **"Yank"**). - Yanked releases remain downloadable by pinned users but are excluded from `pip install` - resolution, giving time to fix without leaving users unpatched. -2. Post a public notice in the GitHub release and on Mastodon explaining the regression and - that the release has been yanked. -3. If the previous (vulnerable) version was also yanked, **un-yank it temporarily** so users - have a functional fallback while the corrected release is prepared. -4. Prepare a corrected point release (incrementing the patch version), repeating sections 7.2–7.3. -5. Document the regression in the post-incident review (Section 9). - -### 7.6 Supply-Chain / Infrastructure Compromise +### 7.5 Supply-Chain / Infrastructure Compromise 1. **Immediately** revoke any potentially compromised credentials: - PyPI API tokens (regenerate and update in GitHub secrets) @@ -199,12 +183,12 @@ If a security patch introduces a critical regression after release: 4. Notify GitHub Security if repository access or Actions secrets are involved. 5. Issue a public advisory describing the scope and any user action required. -### 7.7 Recovery +### 7.6 Recovery After the fix is released and the advisory is public: 1. Verify that the patched wheels are live on PyPI and passing CI across all supported platforms. -2. Confirm any yanked releases are handled correctly (re-yank if un-yanked as a fallback during rollback). +2. Confirm any yanked releases are handled correctly . 3. Resume normal development operations on `main`. 4. Monitor the GitHub issue tracker and Mastodon for user reports of residual problems for at least **72 hours** post-release. 5. Close the private GitHub Security Advisory once recovery is confirmed. From 0d440b7d09b490701f5edf3f0f076bbfdef23afc Mon Sep 17 00:00:00 2001 From: Jeffrey 'Alex' Clark Date: Thu, 9 Apr 2026 18:04:00 -0400 Subject: [PATCH 15/20] Trim Plan Maintenance section Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/INCIDENT_RESPONSE.md | 30 +----------------------------- 1 file changed, 1 insertion(+), 29 deletions(-) diff --git a/.github/INCIDENT_RESPONSE.md b/.github/INCIDENT_RESPONSE.md index c879e4ed9ad..029a6902861 100644 --- a/.github/INCIDENT_RESPONSE.md +++ b/.github/INCIDENT_RESPONSE.md @@ -221,31 +221,7 @@ After the fix is released and the advisory is public: --- -## 9. Post-Incident Review - -Within **2 weeks** of a Critical or High severity fix being released: - -1. Hold a brief retrospective (async is fine for a distributed team). -2. Document the following metrics for the incident record: - - | Metric | Target | Actual | - |---|---|---| - | Time to acknowledge reporter | ≤ 72 hours | | - | Time to reproduce & assess severity | ≤ 5 days | | - | Time to develop & review fix | Varies by severity | | - | Time from report to public release | Critical ≤ 14 days; High ≤ 30 days | | - -3. Record: - - What went well - - What could be improved - - Root cause: what allowed the vulnerability to exist - - Whether any distro/downstream was impacted before the fix was available -4. File follow-up issues for any process improvements identified. -5. Update this document if the response process needs revision. - ---- - -## 10. Dependency Map +## 9. Dependency Map Understanding what Pillow depends on (upstream) and what depends on Pillow (downstream) is essential for scoping impact and coordinating notifications during an incident. @@ -348,10 +324,6 @@ This document is a living record. It should be kept current so it is useful when incident actually occurs. - **Quarterly review** — revisit during the Section 1.3 readiness review at each quarterly release. -- **Post-incident update** — if the response process revealed gaps or needed improvisation, - update this document before the post-incident review is closed (Section 9). -- **Ownership** — changes are approved by the Core Team and recorded in Git history. - Substantive changes should be noted in the PR description so they are easy to find later. --- From 80a91fdb4e90b609e1ad78a3df4cb70cd191be46 Mon Sep 17 00:00:00 2001 From: Jeffrey 'Alex' Clark Date: Thu, 9 Apr 2026 18:08:44 -0400 Subject: [PATCH 16/20] Add setuptools to Python-level dependencies Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/INCIDENT_RESPONSE.md | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/INCIDENT_RESPONSE.md b/.github/INCIDENT_RESPONSE.md index 029a6902861..b82889503f2 100644 --- a/.github/INCIDENT_RESPONSE.md +++ b/.github/INCIDENT_RESPONSE.md @@ -259,6 +259,7 @@ require a Pillow point release even if Pillow's own code is unchanged. | Package | Required? | Purpose | |---|---|---| +| `setuptools` | Build-time only | Package build backend | | `pybind11` | Build-time only | C++ ↔ Python bindings | | `olefile` | Optional (`fpx`, `mic` extras) | OLE2 container parsing (FPX, MIC formats) | | `defusedxml` | Optional (`xmp` extra) | Safe XML parsing for XMP metadata | From 6f815c2d8d088b2d1f87621a7a0d347a5a9052f4 Mon Sep 17 00:00:00 2001 From: Jeffrey 'Alex' Clark Date: Thu, 9 Apr 2026 18:13:43 -0400 Subject: [PATCH 17/20] Clarify advisory thread purpose as reporter coordination Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/INCIDENT_RESPONSE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/INCIDENT_RESPONSE.md b/.github/INCIDENT_RESPONSE.md index b82889503f2..e4473ad33e9 100644 --- a/.github/INCIDENT_RESPONSE.md +++ b/.github/INCIDENT_RESPONSE.md @@ -198,7 +198,7 @@ After the fix is released and the advisory is public: ## 8. Communication ### Internal (during embargo) -- Use the **private GitHub Security Advisory** thread for all coordination. +- Use the **private GitHub Security Advisory** thread for coordination with the reporter. - Do not discuss details in public issues, PRs, or Gitter/IRC channels. ### External (at or after disclosure) From b579577aa0facc8bb03737a8741f81388200f6b6 Mon Sep 17 00:00:00 2001 From: Jeffrey 'Alex' Clark Date: Thu, 9 Apr 2026 18:15:25 -0400 Subject: [PATCH 18/20] Link to section 1.3 in Plan Maintenance Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/INCIDENT_RESPONSE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/INCIDENT_RESPONSE.md b/.github/INCIDENT_RESPONSE.md index e4473ad33e9..3eec4d4e4c5 100644 --- a/.github/INCIDENT_RESPONSE.md +++ b/.github/INCIDENT_RESPONSE.md @@ -324,7 +324,7 @@ When a CVE is published for a bundled C library: This document is a living record. It should be kept current so it is useful when an incident actually occurs. -- **Quarterly review** — revisit during the Section 1.3 readiness review at each quarterly release. +- **Quarterly review** — revisit during the [Section 1.3 readiness review](#13-readiness-review) at each quarterly release. --- From 55989595eaf4774347bec6f147d43a7cd5eb275f Mon Sep 17 00:00:00 2001 From: Jeffrey 'Alex' Clark Date: Thu, 9 Apr 2026 18:17:39 -0400 Subject: [PATCH 19/20] Add private channels note to internal communication guidance Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/INCIDENT_RESPONSE.md | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/INCIDENT_RESPONSE.md b/.github/INCIDENT_RESPONSE.md index 3eec4d4e4c5..7e556728a4d 100644 --- a/.github/INCIDENT_RESPONSE.md +++ b/.github/INCIDENT_RESPONSE.md @@ -199,6 +199,7 @@ After the fix is released and the advisory is public: ### Internal (during embargo) - Use the **private GitHub Security Advisory** thread for coordination with the reporter. +- Use private communication channels for all other coordination. - Do not discuss details in public issues, PRs, or Gitter/IRC channels. ### External (at or after disclosure) From 6fe81dd52e34df4cbfa1b355996e565cb6df9802 Mon Sep 17 00:00:00 2001 From: Jeffrey 'Alex' Clark Date: Thu, 9 Apr 2026 18:19:22 -0400 Subject: [PATCH 20/20] Remove Wand from downstream dependencies Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/INCIDENT_RESPONSE.md | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/INCIDENT_RESPONSE.md b/.github/INCIDENT_RESPONSE.md index 7e556728a4d..e02127cb608 100644 --- a/.github/INCIDENT_RESPONSE.md +++ b/.github/INCIDENT_RESPONSE.md @@ -297,7 +297,6 @@ warrant proactive notification. | [Plone](https://plone.org/) | CMS image handling | | [Jupyter / IPython](https://jupyter.org/) | Inline image display | | [ReportLab](https://www.reportlab.com/) | PDF image embedding | -| [Wand](https://docs.wand-py.org/) | Sometimes used alongside Pillow | | [Tidelift subscribers](https://tidelift.com/) | Enterprise consumers (coordinated via Tidelift) | #### Pillow ecosystem plugins