Pillow/.github/INCIDENT_RESPONSE.md
Jeffrey 'Alex' Clark 6e1ccab749 Address review feedback on INCIDENT_RESPONSE.md
- Update CVSS v3.1 to CVSS 4.0 throughout
- Remove 'Direct maintainer contact' from detection sources
- Fix 'before it stays public' wording for user bug reports
- Simplify sections 7.3 and 7.4 to reference RELEASING.md instead
  of duplicating release process steps
- Update RELEASING.md Point release section with security-specific
  steps (amend CVE in commits, publish GitHub Security Advisory)
- Fix PyPI API tokens entry (remove GitHub secrets reference)
- Fix 404 PyPI manage URL (use correct case and /releases/ path)
- Replace security@pypi.org mailto with https://pypi.org/security/
- Remove unconfirmed 'Notify GitHub Security' bullet
- Fix section numbering: 10.x → 9.x under Section 9. Dependency Map
- Reorder: move 9.3 Responding to Upstream Vulnerability before 9.3
  Downstream Dependencies (now 9.2 and 9.3 respectively)
- Add anchor link for Section 5 reference in 9.2
- Add #plugin-list anchor to third-party plugins handbook link
- Fix GitLab issue tracker URLs to use /-/work_items for libtiff,
  freetype2, and bzip2
- Add pyproject.toml reference for complete optional dependencies list

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-10 10:58:43 -04:00

20 KiB
Raw Blame History

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 and Release Checklist.


1. Preparation

Maintaining readiness before an incident occurs reduces response time and errors under pressure.

1.1 Version Support Matrix

Security fixes are applied to the latest stable release only. Users on older versions are expected to upgrade. Reporters should assume only the latest release will receive a patch.

Branch Status
main / latest stable Security fixes applied
All older releases No security support — please upgrade

1.2 Team Readiness

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 Readiness Review

At each quarterly release, maintainers should re-read this document and update any stale content.


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. 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
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.
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.

One person may fill multiple roles.


5. Severity Classification

Use the CVSS 4.0 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 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

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.


6. Detection Sources

Vulnerabilities and incidents may be reported or discovered through:

  1. GitHub private security advisory — preferred channel; see SECURITY.md
  2. Tidelift security contacthttps://tidelift.com/security
  3. External researcher / coordinated disclosure — e.g. Google Project Zero, vendor PSIRT
  4. Automated scanning — Dependabot, GitHub code-scanning (CodeQL), CI fuzzing
  5. Distro security teams — Debian, Red Hat, Ubuntu, Alpine may report upstream
  6. User bug report — public issue (reassess if it has security implications and convert to a private advisory if needed)

7. Response Process

7.1 Triage (all severities)

  1. Acknowledge receipt to the reporter within 72 hours using the template in Appendix A. 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 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.
  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. Escalation — Escalate beyond the core maintainer team if any of the following apply:
    • 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

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.
  2. Write a regression test that fails before the fix and passes after.
  3. Review the patch with at least one other maintainer.

7.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).
  2. Amend commit messages to include the CVE identifier.
  3. Follow the Point release process in RELEASING.md to tag, push, and confirm wheels are live on PyPI.
  4. Publish the GitHub Security Advisory (this simultaneously publishes the CVE).

7.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 714 days out, up to 90 days for complex issues).
  3. Privately send the patch to distros via the linux-distros mailing list or directly to individual distro security teams.
  4. On the embargo date:
    • Amend commit messages with the CVE identifier.
    • Follow the Embargoed release process in RELEASING.md to tag, push, and confirm wheels are live on PyPI.
    • Publish the GitHub Security Advisory.

7.5 Supply-Chain / Infrastructure Compromise

  1. Immediately revoke any potentially compromised credentials:
    • PyPI API tokens
    • 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 the PyPI release management page (login required); see https://pypi.org/security/ for reporting to the PyPI security team.
  4. Issue a public advisory describing the scope and any user action required.

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 .
  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.

8. Communication

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)

Audience Channel Timing
General users GitHub Security Advisory 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 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 (python3 -m pip install --upgrade Pillow)

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 JPEG encode/decode GitHub
libpng PNG encode/decode SourceForge
libtiff TIFF encode/decode GitLab
libwebp WebP encode/decode Chromium tracker
libavif AVIF encode/decode GitHub
aom AV1 codec (AVIF) Chromium tracker
dav1d AV1 decode (AVIF) VideoLAN Security
openjpeg JPEG 2000 encode/decode GitHub
freetype2 Font rendering GitLab
lcms2 ICC color management GitHub
harfbuzz Text shaping (via raqm) GitHub
raqm Complex text layout GitHub
fribidi Unicode bidi (via raqm) GitHub
zlib Deflate compression zlib.net
liblzma / xz-utils XZ/LZMA compression GitHub
bzip2 BZ2 compression GitLab
zstd Zstandard compression GitHub
brotli Brotli compression GitHub
libyuv YUV conversion Chromium tracker

Python-level dependencies

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

See pyproject.toml for the complete and authoritative list of optional dependencies.

9.2 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: Severity Classification.
  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.

9.3 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 / Ubuntu Security
Fedora / RHEL / CentOS python3-pillow Red Hat Security
Alpine Linux py3-pillow Alpine security
Arch Linux python-pillow Arch security tracker
Homebrew pillow Homebrew maintainers
conda-forge pillow conda-forge

Major Python ecosystem consumers

These are high-profile projects known to depend on Pillow; a critical vulnerability may warrant proactive notification.

Project Usage
matplotlib Image I/O for plots
scikit-image Image processing
torchvision (PyTorch) Dataset loading, transforms
Keras / TensorFlow Image preprocessing utilities
Django ImageField validation and thumbnail generation
Wagtail CMS image renditions
Plone CMS image handling
Jupyter / IPython Inline image display
ReportLab PDF image embedding
Tidelift subscribers 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.


11. Plan Maintenance

This document is a living record. It should be kept current so it is useful when an incident actually occurs. Revisit it during the Section 1.3 readiness review at each quarterly release.


12. References


Appendix A: Communication Templates

A.1 Reporter Acknowledgment

Subject: Re: [Security] <brief issue description>

Hi <name>,

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 — <CVE-XXXX-XXXXX> — disclosure <DATE>

This is an embargoed notification of a vulnerability in Pillow. Please keep this information confidential until the disclosure date listed below.

CVE: <CVE-XXXX-XXXXX> Affected versions: <e.g. Pillow < 11.x.x> Fixed version: <version> Severity: <Critical / High / Medium / Low> (CVSS <score>: <vector>) Reporter: <name / affiliation, or "reported privately"> Public disclosure date: <DATE TIME UTC>

Summary: <One paragraph describing the vulnerability class and impact without a full exploit.>

Proof of concept: <Minimal reproducer or attached patch.>

Remediation: Upgrade to Pillow <fixed version>. 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: <One-paragraph technical summary.>

CVE: <CVE-XXXX-XXXXX> Affected versions: Pillow < <fixed version> Fixed version: <version> Severity: <rating> (CVSS <score>) Reporter: <credited name / "reported privately">

Details: <Fuller technical description. Include attack scenario where helpful.>

Remediation:

python3 -m pip install --upgrade Pillow

Timeline:

  • Reported: <date>
  • Fixed: <date>
  • Disclosed: <date>