Skip to content

Fail closed when an upload's owning book can't be resolved - #486

Merged
jeremy merged 2 commits into
mainfrom
security/uploads-fail-closed-nil-book
Sep 1, 2026
Merged

Fail closed when an upload's owning book can't be resolved#486
jeremy merged 2 commits into
mainfrom
security/uploads-fail-closed-nil-book

Conversation

@jeremy

@jeremy jeremy commented Aug 31, 2026

Copy link
Copy Markdown
Member

ActionText::Markdown::UploadsController#ensure_attachment_readable listed @book.nil? as the first allowed condition:

head :not_found unless @book.nil? || @book.published? || @book.accessable?

When set_attachment can't resolve an owning book — @attachment.record.try(:record).try(:owning_book) returns nil — the nil? branch short-circuits the guard and the file is served (and, for the show path, potentially cached publicly). That's the opposite of the invariant the guard exists to hold: an unpublished book's uploads are as private as the book itself.

A live attachment reaches a nil owning book when its leaf is severed without the destroy cascade that would otherwise purge the attachment along with its markdown record. The guard should treat "no book to authorize against" as deny, not allow.

Fix

Drop the nil branch and use safe navigation, so a nil book fails both checks and 404s:

head :not_found unless @book&.published? || @book&.accessable?

Published and accessible books are unaffected — every existing serving test still passes.

Test

Adds a regression test: an attachment whose owning book can't be resolved is not served (404), asserted for an anonymous client against an unpublished book.

Copilot AI balanced review requested due to automatic review settings August 31, 2026 13:39
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Aug 31, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-08-31T20:05:32.015627Z 836336e New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fails closed when an upload’s owning book cannot be resolved, preventing unauthorized serving or public caching.

Changes:

  • Denies access when @book is nil.
  • Adds regression coverage for orphaned attachments.

Tip

If you aren't ready for review, convert to a draft PR.
Click "Convert to draft" or run gh pr ready --undo.
Click "Ready for review" or run gh pr ready to reengage.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
app/controllers/action_text/markdown/uploads_controller.rb Makes attachment authorization fail closed.
test/controllers/action_text/markdown/uploads_controller_test.rb Tests unresolved owning-book access.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread test/controllers/action_text/markdown/uploads_controller_test.rb Outdated
ensure_attachment_readable listed @book.nil? as the first allowed
condition, so an attachment whose owning book couldn't be resolved
short-circuited the check and was served — the opposite of the
unpublished-uploads-stay-private invariant the guard exists to hold. A
live attachment reaches this state when its leaf is severed without the
destroy cascade that would otherwise purge it.

Drop the nil branch and use safe navigation, so a nil book fails the
check and 404s. Published/accessible books are unaffected.
@jeremy
jeremy force-pushed the security/uploads-fail-closed-nil-book branch from b6e6fbb to 4af0220 Compare August 31, 2026 13:42

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b6e6fbbb8a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread test/controllers/action_text/markdown/uploads_controller_test.rb Outdated
Matches the AGENTS.md controller/integration-test convention; no
cross-host or absolute-URL behavior is under test here.
@jeremy
jeremy merged commit 2055ce1 into main Sep 1, 2026
7 checks passed
@jeremy
jeremy deleted the security/uploads-fail-closed-nil-book branch September 1, 2026 02:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants