Readest quote about improving the security and integrity of reading data beside GitHub Secure Open Source Fund artwork.

Readest in the GitHub Secure Open Source Fund

Three weeks set aside for threat modeling, code scanning, incident response, and the less visible work of keeping readers safe.

chrox
chrox
5 min read·

Security work rarely arrives at a convenient time. There is always a reading bug to fix, a rough edge to smooth out, or a release that users are waiting for. On a young open-source project, it is easy to spend another week on the work people can see and leave the threat model for later.

Readest has now completed Session 4 of the GitHub Secure Open Source Fund, a three-week program run with the GitHub Security Lab. It gave us dedicated time, direct guidance from security experts, and a small community of maintainers doing the same work on their own projects.

GitHub Secure Open Source Fund artwork with logos from Session 4 funding partners.
Readest was one of 50 open-source projects in Session 4 of the GitHub Secure Open Source Fund.

Why this matters for a reading app

Books feel harmless. The files are not.

An EPUB is a container full of HTML, CSS, images, fonts, and other files. PDFs have their own long history of complicated parsers. A reader accepts these documents from email attachments, download sites, shared folders, and personal archives, then unpacks and renders them. Every import crosses a trust boundary.

Readest also holds the quiet record of a person's reading life: books, highlights, notes, and reading positions. We build Readest to be local-first because that data belongs to the reader. But local-first does not remove the need for security. It makes the responsibility more concrete. We have to protect the files on the device, the code that opens them, and the path that carries a release from our repository to the reader.

We had security checks before the program, but they did not yet add up to one clear model. The three-week sprint gave us the time to step back and connect them.

What we changed

We began with threat modeling: what Readest needs to protect, where data enters the application, which components trust one another, and what an attacker might control. That exercise changed the order of our questions. Instead of asking how to secure a feature after it works, we now start with the data and its boundaries.

The clearest attack surface was book ingestion. We reviewed the pipeline that parses, sanitizes, and renders EPUB, PDF, and HTML content. We tightened those paths and enforced stricter content security policies. There is more to do here, especially around systematic validation and sandboxing, but the boundary is now explicit rather than assumed.

We also looked closely at the software supply chain. Readest depends on third-party packages and GitHub Actions to test and ship releases across several platforms. We enabled automated CodeQL scanning, reviewed our Actions workflows and permissions, and moved them toward safer defaults. A reading app can have careful application code and still be exposed by an overpowered workflow or a compromised dependency; our threat model now treats the release machinery as part of the product.

Finally, we worked on what happens when prevention fails. We began formalizing how we receive a private vulnerability report, assess it, prepare a fix, and disclose it responsibly. An incident response plan is easy to postpone during normal development. Writing it before an incident is what makes it useful.

What stayed with us

The change we expect to last longest is simple: we now treat security as design work.

For Readest, that means asking a few questions early: What user data does this feature touch? Which input can be controlled by somebody else? What crosses from web content into native code? Which dependency or workflow is allowed to publish a release? These questions are much cheaper before code is shipped than after a report lands in the inbox.

We also spent time on AI-assisted security work. It can help explore a threat model, review unfamiliar code, and sort through alerts. It cannot supply the project context or make the final judgment about what is safe to ship. The useful balance is the same one GitHub saw across the Session 4 cohort: tools can shorten the loop, while maintainers remain responsible for the decision.

The other lasting part was the group itself. Open-source maintenance can be oddly solitary, especially when the subject is a security gap you are not ready to discuss in public. Comparing threat models and incident plans with other maintainers made the work less abstract. We came away with practical ideas, but also with people we can ask when a difficult case appears.

The work from here

At the end of the session, we had a short list of work we intend to finish:

  • Finish the threat model around reading data, file parsing, and future sync features.
  • Complete our incident response and disclosure process.
  • Add stricter validation and sandboxing for untrusted book content.
  • Keep tightening dependencies, Actions workflows, and release permissions.
  • Make our security guidance clearer for contributors and make private reporting easy to find.

We also want to pass the lessons on. Readest is used by readers, but it is built with contributors. Clear secure-by-design habits help both groups, and the same thinking applies to many projects that accept files or keep personal data on a device.

We are grateful to GitHub, the GitHub Security Lab, the program partners, and the maintainers who shared three packed weeks with us. The funding mattered for a plain reason: it paid for maintainer time. Those weeks helped us make Readest safer today and gave us a better way to build what comes next. Thank you to GitHub for continuing to invest in the security of open source.

You can read GitHub's full Session 4 report or follow our security work in the Readest repository.