Skip to content

fix(security): enforce studio ownership on movie lookups (Closes #251) - #445

Merged
SRV30 merged 1 commit into
SRV30:mainfrom
SakethSumanBathini:fix/251-idor-movie-ownership
Aug 5, 2026
Merged

fix(security): enforce studio ownership on movie lookups (Closes #251)#445
SRV30 merged 1 commit into
SRV30:mainfrom
SakethSumanBathini:fix/251-idor-movie-ownership

Conversation

@SakethSumanBathini

Copy link
Copy Markdown
Contributor

Closes #251

Six sites, not four

The issue names releaseMovie, getMovieDetails, getMovieTracking and addMarketingCampaign. Auditing every Movie lookup in the controller turned up two more with the identical flaw:

Controller Line Reported
releaseMovie 264
scheduleRelease 301 also vulnerable
getMovieDetails 343
getMovieTracking 359
addMarketingCampaign 398
reReleaseMovie 475 also vulnerable

All six used Movie.findById(id) with no ownership filter, so any authenticated user could read or act on any movie by ID.

addMarketingCampaign was the worst of them

It fetched the movie with no check, then fetched the caller's studio and deducted funds from it:

movie = await Movie.findById(id).session(session);       // no ownership check
...
studio = await Studio.findOne({ owner: req.user._id });  // caller's own studio
if (studio.money < campaign.cost) { ... }                // caller pays

So you could pay to promote a rival studio's film — boosting their box office with your money — or drain your own balance by repeating the call against any ID. The order is now inverted: the studio is resolved first, inside the transaction, and the movie query filters on it.

The fix follows the pattern already in this file

getReleasedMovies at line 327 already did this correctly:

const studio = await Studio.findOne({ owner: req.user._id }).select("_id").lean();
const movie  = await Movie.findOne({ _id: id, studioId: studio._id });

Ownership is enforced in the query, not after it. Two consequences worth naming:

  • A movie belonging to another studio is never loaded into memory, so there's no window where unauthorised data exists in the process.
  • The 404 covers both "no such movie" and "not yours", so a caller probing IDs can't distinguish them. A post-fetch if (movie.studioId !== studio._id) return 403 would leak existence.

releaseMovie and reReleaseMovie use ownerStudio for the check because both already declare a separate studio later — a full mutable document they need for .save(). Keeping the names distinct avoids shadowing.

Verification

  • node --check clean on the modified file.
  • Zero remaining Movie.findById calls in the controller; all six lookups now carry studioId.
  • Authorization semantics modelled directly:
Alice requests her own m1     -> Alice's film
Alice requests Bob's m2       -> 404 Movie not found
Before the fix, same request  -> Bob's film   <- leaked

I couldn't run the backend suite: tests/testScreening.test.js needs MongoMemoryServer, which downloads a MongoDB binary my environment can't reach. It fails identically on unmodified elusoc, so it's an environment limit rather than a regression — but a live run against a real database is worth doing before merge.

Note on PR #329

@Sairaj2033's #329 targets this issue and is still open. I raised the overlap with @SRV30 before starting and was asked to proceed. That PR also carries three unrelated fixes (route shadowing, notification error handling, spy transactions) which this PR does not touch, so those remain worth taking from it independently.

@vercel

vercel Bot commented Aug 4, 2026

Copy link
Copy Markdown

@SakethSumanBathini is attempting to deploy a commit to the srv30's projects Team on Vercel.

A member of the Team first needs to authorize it.

@SRV30 SRV30 added elusoc Official ELUSOC 2026 issue. Contributions on these issues are eligible for ELUSOC participation. newbie Beginner-friendly tasks suitable for first-time contributors. (10 XP) labels Aug 5, 2026
@SRV30
SRV30 merged commit e0350a4 into SRV30:main Aug 5, 2026
2 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

elusoc Official ELUSOC 2026 issue. Contributions on these issues are eligible for ELUSOC participation. newbie Beginner-friendly tasks suitable for first-time contributors. (10 XP)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ECSoC_2026 & ELUSOC_2026 Security: IDOR allows unauthorized access to private movie data

2 participants