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")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)
- Log in as User A.
- Navigate to your own shelf at
/shelf/edit/2. - Intercept the outbound
POSTrequest and modify the path parameter from/shelf/edit/2to/shelf/edit/1(which belongs to User B). - 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:
- The currently authenticated user is the owner of the shelf (
shelf.user_id == current_user.id), OR - 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'))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
Repository:janeczku/calibre-web
Fix commit:Commit c7b057e - merged from Ileana's commit
Huntr bounty report:Bounty #458c313f



Top comments (0)