Skip to content

fix: resolve 7 bugs across API routes (security, logic, edge cases)#9

Open
Programmer-Develops wants to merge 7 commits intoJavaScript-Mastery-Pro:mainfrom
Programmer-Develops:fix/programmerdevelops
Open

fix: resolve 7 bugs across API routes (security, logic, edge cases)#9
Programmer-Develops wants to merge 7 commits intoJavaScript-Mastery-Pro:mainfrom
Programmer-Develops:fix/programmerdevelops

Conversation

@Programmer-Develops
Copy link
Copy Markdown

@Programmer-Develops Programmer-Develops commented Apr 18, 2026

Summary

Fixed 7 predefined bugs across API route handlers covering security vulnerabilities, logic errors, and edge cases.

Fixes

  1. fix: add await to Grade.findOneAndUpdate (app/api/grades/route.ts)

    • Was returning a Promise object instead of the resolved grade document
  2. fix: default maxMarks to 100 when undefined (app/api/grades/route.ts)

    • maxMarks is optional in the schema; using ! caused calcGrade to receive undefined, producing wrong letter grades
  3. fix: validate and use parsed result in POST /api/students (app/api/students/route.ts)

    • safeParse result was never checked; raw unvalidated body was passed directly to Student.create()
  4. fix: prevent IDOR in GET /api/profile (app/api/profile/route.ts)

    • userId was accepted as a query param, allowing any authenticated user to fetch another teacher's profile by passing an arbitrary userId
  5. fix: scope mutations to authenticated teacherId (grades/[id], students/[id], assignments/[id])

    • PUT and DELETE queries filtered only by _id, allowing any authenticated teacher to modify or delete another teacher's records
  6. fix: replace error.stack with generic message in 500 responses (grades/route.ts, assignments/route.ts)

    • Stack traces with internal file paths and line numbers were being sent to the client
  7. fix: return 400 not 404 for invalid ObjectId in PUT /api/grades/[id]

    • An invalid ID format is a bad request, not a not-found error (consistent with other routes)

Issues Fixed: 7

Summary by CodeRabbit

  • Bug Fixes

    • Fixed asynchronous operation in grade creation workflow
    • Strengthened input validation for student record submissions
    • Standardized error response formats across API endpoints
  • Security

    • Restricted assignment, grade, and student data access to the authenticated teacher
    • Removed sensitive error details from API responses
    • Enhanced authentication enforcement for profile endpoint

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 18, 2026

📝 Walkthrough

Walkthrough

Multiple API endpoints were updated to enhance authorization enforcement and error handling. Ownership checks (teacherId validation) were added to mutation endpoints. Error responses were standardized to exclude stack traces. Validation logic was improved with explicit Zod result checking, and authentication flow was simplified.

Changes

Cohort / File(s) Summary
Resource Authorization Scoping
app/api/assignments/[id]/route.ts, app/api/grades/[id]/route.ts, app/api/students/[id]/route.ts
PUT and DELETE handlers now filter by both _id and teacherId, restricting updates/deletions to authenticated teacher's resources only.
Error Response Standardization
app/api/assignments/route.ts, app/api/grades/route.ts
Error responses simplified; 500 responses now return fixed { error: 'Internal server error' } payload instead of stack traces.
Validation & Database Operations
app/api/students/route.ts, app/api/grades/route.ts
Explicit Zod validation result checking with treeifyError; added await to findOneAndUpdate to ensure async completion; changed maxMarks default from non-null assertion to coalescing (?? 100).
Authentication Flow
app/api/profile/route.ts
Removed NextRequest parameter and query string fallback; userId now derives solely from auth() with 401 response if absent.
Validation Response
app/api/grades/[id]/route.ts
Invalid ObjectId now returns 400 "Invalid id" instead of 404 "Not found".

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 With whiskers twitch and thumping feet,
We've locked the doors—the code's now neat!
Each teacher guards their own affairs,
No stack traces floating through the airs,
Validation checked, no stone unturned,
Security's the lesson we have learned!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main objective: fixing seven bugs across API routes addressing security, logic, and edge cases.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
app/api/grades/[id]/route.ts (1)

56-63: ⚠️ Potential issue | 🟡 Minor

DELETE is missing ObjectId validation — inconsistent with sibling routes and with the new PUT behavior.

An invalid id reaches Grade.findOneAndDelete and triggers a Mongoose CastError caught as 500 instead of 400. Both app/api/assignments/[id]/route.ts (lines 60-63) and app/api/students/[id]/route.ts (lines 62-65) validate here, and the PR already aligned PUT to return 400 on invalid id — DELETE should match.

🛠️ Proposed fix
   try {
     const { id } = await ctx.params
+
+    // Validate ObjectId
+    if (!mongoose.Types.ObjectId.isValid(id)) {
+      return NextResponse.json({ error: 'Invalid id' }, { status: 400 })
+    }
+
     await connectDB()
     const deleted = await Grade.findOneAndDelete({ _id: id, teacherId: userId })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/api/grades/`[id]/route.ts around lines 56 - 63, The DELETE handler is
missing ObjectId validation causing invalid ids to bubble into
Grade.findOneAndDelete and produce a 500; before calling
connectDB/Grade.findOneAndDelete, validate the extracted id (from ctx.params)
using Mongoose's ObjectId validation (e.g. mongoose.isValidObjectId or
Types.ObjectId.isValid) and if invalid return NextResponse.json({ error:
'Invalid id' }, { status: 400 }) to match the PUT and sibling routes (ensure
this check occurs before calling connectDB and before invoking
Grade.findOneAndDelete).
app/api/grades/route.ts (1)

49-53: ⚠️ Potential issue | 🟠 Major

Stack-trace leak in GET handler was NOT fixed — PR objective is incomplete.

Line 51 still returns error.stack in the 500 response body, which the PR description explicitly targets ("grades/route.ts … replace error.stack with a generic message in 500 responses"). Only the POST handler below was updated. Stack traces expose internal file paths, dependency internals, and can aid attackers. Please apply the same fix here.

🛡️ Proposed fix
   } catch (error) {
-    console.error('GET /api/grades error:', error instanceof Error ? error.message : error)
-    return NextResponse.json({ error: error instanceof Error ? error.stack : 'Internal server error' }, { status: 500 })
+    if (error instanceof Error) {
+      console.error('GET /api/grades error:', error.message)
+    }
+    return NextResponse.json({ error: 'Internal server error' }, { status: 500 })
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/api/grades/route.ts` around lines 49 - 53, The GET handler's catch block
in app/api/grades/route.ts still returns error.stack in the 500 JSON response;
update the catch for the GET (the try/catch surrounding the GET handler
function) to return a generic message (e.g., "Internal server error") instead of
error.stack, while keeping or enhancing the existing console.error('GET
/api/grades error:', ...) to log the actual error/stactrace server-side for
debugging; ensure the change mirrors the POST handler fix so no stack traces are
exposed in responses.
🧹 Nitpick comments (2)
app/api/students/route.ts (1)

95-99: Correct fix for the unvalidated-input bug; minor inconsistency to consider.

Using parsed.data instead of body in Student.create prevents callers from injecting unknown fields (e.g., teacherId, _id) into the document. This is the right fix.

One minor inconsistency: app/api/assignments/route.ts and app/api/grades/route.ts return validation errors with parsed.error.flatten(), while this endpoint returns z.treeifyError(parsed.error). The two produce different shapes — front-end error handling becomes branchy. Consider standardizing.

♻️ Optional alignment with other routes
-    if (!parsed.success) return NextResponse.json({ error: z.treeifyError(parsed.error) }, { status: 400 })
+    if (!parsed.success) return NextResponse.json({ error: parsed.error.flatten() }, { status: 400 })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/api/students/route.ts` around lines 95 - 99, The Student create handler
correctly uses StudentSchema.safeParse and must continue to pass parsed.data to
Student.create to avoid unvalidated fields (see StudentSchema and Student.create
usage), but standardize the validation error shape to match other endpoints by
replacing z.treeifyError(parsed.error) with parsed.error.flatten() (used by
app/api/assignments/route.ts and app/api/grades/route.ts) in the
NextResponse.json call so all routes return a consistent error payload via
NextResponse.json.
app/api/grades/route.ts (1)

72-80: Targeted fixes look correct.

  • data.maxMarks ?? 100 aligns with the schema default (models/Grade.ts line 28).
  • Adding await to Grade.findOneAndUpdate ensures the resolved document is returned (previously the response serialized a pending promise).
  • On the upsert-create path, ...data spreads maxMarks: undefined when omitted; Mongoose drops undefined and the schema default (100) applies, so behavior is consistent — but explicitly setting maxMarks: max in $set would make intent clearer.
♻️ Optional clarity tweak
-      { $set: { ...data, term, teacherId: userId, grade: calcGrade(data.marks, max) } },
+      { $set: { ...data, maxMarks: max, term, teacherId: userId, grade: calcGrade(data.marks, max) } },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/api/grades/route.ts` around lines 72 - 80, The upsert currently spreads
...data into the $set which can leave maxMarks undefined and rely on Mongoose
defaults; explicitly set maxMarks to the computed max so intent is clear and
calcGrade uses the same value — update the Grade.findOneAndUpdate call to
include maxMarks: max inside the $set (alongside term, teacherId and grade
computed by calcGrade(data.marks, max)), ensuring the code uses the existing max
variable and the calcGrade function for consistency.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@app/api/grades/`[id]/route.ts:
- Around line 56-63: The DELETE handler is missing ObjectId validation causing
invalid ids to bubble into Grade.findOneAndDelete and produce a 500; before
calling connectDB/Grade.findOneAndDelete, validate the extracted id (from
ctx.params) using Mongoose's ObjectId validation (e.g. mongoose.isValidObjectId
or Types.ObjectId.isValid) and if invalid return NextResponse.json({ error:
'Invalid id' }, { status: 400 }) to match the PUT and sibling routes (ensure
this check occurs before calling connectDB and before invoking
Grade.findOneAndDelete).

In `@app/api/grades/route.ts`:
- Around line 49-53: The GET handler's catch block in app/api/grades/route.ts
still returns error.stack in the 500 JSON response; update the catch for the GET
(the try/catch surrounding the GET handler function) to return a generic message
(e.g., "Internal server error") instead of error.stack, while keeping or
enhancing the existing console.error('GET /api/grades error:', ...) to log the
actual error/stactrace server-side for debugging; ensure the change mirrors the
POST handler fix so no stack traces are exposed in responses.

---

Nitpick comments:
In `@app/api/grades/route.ts`:
- Around line 72-80: The upsert currently spreads ...data into the $set which
can leave maxMarks undefined and rely on Mongoose defaults; explicitly set
maxMarks to the computed max so intent is clear and calcGrade uses the same
value — update the Grade.findOneAndUpdate call to include maxMarks: max inside
the $set (alongside term, teacherId and grade computed by calcGrade(data.marks,
max)), ensuring the code uses the existing max variable and the calcGrade
function for consistency.

In `@app/api/students/route.ts`:
- Around line 95-99: The Student create handler correctly uses
StudentSchema.safeParse and must continue to pass parsed.data to Student.create
to avoid unvalidated fields (see StudentSchema and Student.create usage), but
standardize the validation error shape to match other endpoints by replacing
z.treeifyError(parsed.error) with parsed.error.flatten() (used by
app/api/assignments/route.ts and app/api/grades/route.ts) in the
NextResponse.json call so all routes return a consistent error payload via
NextResponse.json.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: cc27aa22-9979-4bae-a0c2-01948f6f084e

📥 Commits

Reviewing files that changed from the base of the PR and between c71cbbf and 3d9c508.

📒 Files selected for processing (7)
  • app/api/assignments/[id]/route.ts
  • app/api/assignments/route.ts
  • app/api/grades/[id]/route.ts
  • app/api/grades/route.ts
  • app/api/profile/route.ts
  • app/api/students/[id]/route.ts
  • app/api/students/route.ts

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.

1 participant