DEV Community

Cover image for 🐛 The bug: Improper Access Control (IDOR) in Calibre-Web
Ileana Barrionuevo
Ileana Barrionuevo

Posted on

🐛 The bug: Improper Access Control (IDOR) in Calibre-Web

Summer Bug Smash: Smash Stories 🐛🛹

This is a submission for DEV's Summer Bug Smash: Smash Stories powered by Sentry.

While auditing janeczku/calibre-web, an open-source web application for browsing, reading, and downloading eBooks stored in a Calibre database, I identified an Insecure Direct Object Reference (IDOR) vulnerability (CWE-284) rated High Severity (CVSS 8.1).

The issue allowed any authenticated user to edit the titles of bookshelf collections owned by other users across the application.


🏆 Bounty milestone

I'm excited to share that this report earned both disclosure and fix bounties on the Huntr bug bounty platform!

  • Discovery & disclosure bounty: awarded for uncovering and detailing the initial IDOR vulnerability.

  • Fix bounty: awarded for authoring and submitting the patch directly upstream to resolve the issue in the codebase.


🕵️‍♂️ Technical deep dive & discovery

The vulnerability existed within the shelf routing logic inside cps/shelf.py (specifically at line 237).

When a user submitted an edit for a shelf, the edit_shelf route queried the database strictly using the shelf_id passed directly from the URL path:

@shelf.route("/shelf/edit/<int:shelf_id>",methods=["GET","POST"])@login_requireddefedit_shelf(shelf_id):shelf=ub.session.query(ub.Shelf).filter(ub.Shelf.id==shelf_id).first()returncreate_edit_shelf(shelf,title=_(u"Edit a shelf"),page="shelfed")
Enter fullscreen modeExit fullscreen mode

Because the application failed to verify whether the logged-in user actually owned the queried shelf_id before passing it to create_edit_shelf(), authorization checks were bypassed completely.

Proof of Concept (PoC)

  1. Log in as User A.
  2. Navigate to your own shelf at /shelf/edit/2.
  3. Intercept the outbound POST request and modify the path parameter from /shelf/edit/2 to /shelf/edit/1 (which belongs to User B).
  4. Submit the request. The server accepts the payload and overwrites User B's shelf title.

🛠️ The fix

To remediate the vulnerability, a proper ownership check needed to be enforced before any shelf modification logic executed.

In Commit `c7b057e`, the routing logic was updated to validate that either:

  1. The currently authenticated user is the owner of the shelf (shelf.user_id == current_user.id), OR
  2. The shelf is public/the user holds administrative privileges allowing edits.
# Updated authorization check enforcing ownership validation
ifshelf.is_public!=1andshelf.user_id!=current_user.idandnotcurrent_user.role_admin():flash(_(u"Sorry you are not allowed to edit this shelf"),category="error")returnredirect(url_for('web.index'))
Enter fullscreen modeExit fullscreen mode

If an unauthorized user attempts to manipulate the path parameter, the request is denied, an error notification is flashed, and the user is redirected safely.


💡 Key takeaways

  • Never trust path parameters for access control: resource identifiers passed via parameters must always be validated against the active session user's permissions backend-side.

  • Full-cycle security contributions: uncovering security flaws is impactful, but submitting valid code patches to open-source maintainers—and earning a fix bounty along the way—makes the open-source ecosystem far more resilient.


Associated links

Top comments (0)