Summary
Two interview routes in server/routes/interviewRoutes.js perform sensitive operations — reading full interview data and submitting analyzed answers — without verifying the caller's identity or ownership of the interview record.
Affected routes
GET /:interviewId (line ~120)
router.get("/:interviewId", async (req, res) => {
const interview = await Interview.findById(req.params.interviewId);
res.json(interview); // no firebaseAuthMiddleware, no ownership check
});
Any unauthenticated caller who knows (or can guess) a valid MongoDB ObjectId can retrieve another user's full interview record, including resume_link, job_description, company_description, and all generated questions.
POST /:interviewId/answer (line ~130)
router.post("/:interviewId/answer", async (req, res) => {
const interview = await Interview.findById(req.params.interviewId);
// ... runs AI analysis and appends to report ...
await report.save(); // no firebaseAuthMiddleware, no ownership check
});
Any unauthenticated caller can submit fabricated answers for any interview ID. The server runs AI analysis and appends the fake answer to the report as if it came from the legitimate owner. If all questions are answered this way the report's finalScore, strengths, and summary are computed from attacker-supplied content.
Contrast with other routes
POST /setup and GET / (list all interviews) correctly use firebaseAuthMiddleware. The two routes above are missing it.
Impact
- Private interview content (resume links, job descriptions, AI questions) is readable by anyone.
- Interview reports can be corrupted or forged by third parties without the account holder's knowledge.
- AI inference costs are incurred for unauthenticated requests with no rate gate.
Suggested Fix
Add firebaseAuthMiddleware to both routes and verify the resolved user._id matches interview.user_id before reading or writing:
router.get("/:interviewId", firebaseAuthMiddleware, async (req, res) => {
const firebaseUID = req.firebaseUser?.uid;
const user = await User.findOne({ firebase_user_id: firebaseUID });
const interview = await Interview.findById(req.params.interviewId);
if (!interview || !interview.user_id.equals(user._id)) {
return res.status(403).json({ error: "Forbidden" });
}
res.json(interview);
});
Apply the same ownership check to POST /:interviewId/answer.
Summary
Two interview routes in
server/routes/interviewRoutes.jsperform sensitive operations — reading full interview data and submitting analyzed answers — without verifying the caller's identity or ownership of the interview record.Affected routes
GET /:interviewId (line ~120)
Any unauthenticated caller who knows (or can guess) a valid MongoDB ObjectId can retrieve another user's full interview record, including
resume_link,job_description,company_description, and all generated questions.POST /:interviewId/answer (line ~130)
Any unauthenticated caller can submit fabricated answers for any interview ID. The server runs AI analysis and appends the fake answer to the report as if it came from the legitimate owner. If all questions are answered this way the report's
finalScore,strengths, andsummaryare computed from attacker-supplied content.Contrast with other routes
POST /setupandGET /(list all interviews) correctly usefirebaseAuthMiddleware. The two routes above are missing it.Impact
Suggested Fix
Add
firebaseAuthMiddlewareto both routes and verify the resolveduser._idmatchesinterview.user_idbefore reading or writing:Apply the same ownership check to
POST /:interviewId/answer.