Skip to content

Security: API Source Code Disclosure via Submission IDOR + Contest PDF Authorization Bypass #1089

@lighthousekeeper1212

Description

@lighthousekeeper1212

Summary

Security audit identified 5 vulnerabilities (2 Critical, 2 High, 1 Medium) in NOJ's authorization logic, primarily in the API endpoints.

Findings

1. API Submission Info IDOR - Source Code Disclosure (CRITICAL)

File: app/Http/Controllers/Api/SubmissionController.php:15

The POST /api/submission/info endpoint returns the full submission record including solution (source code) for ANY submission. The api.submission.exist middleware only checks that the submission exists (Submission::find($request->sid)) but performs no ownership check.

Any authenticated API user can read any other user's source code by iterating submission IDs — enabling cheating during contests.

Contrast: The web Ajax/SubmissionController@detail correctly uses getJudgeStatus() which nulls out the solution field for non-owned submissions. The API bypasses this entirely.

2. API fetchVerdict IDOR - Source Code Disclosure (CRITICAL)

File: app/Http/Controllers/Api/ProblemController.php:38

POST /api/problem/fetchVerdict explicitly returns "solution" => $submission->solution for ANY submission. Same root cause — api.submission.exist middleware lacks ownership check.

3. Contest PDF Download Missing Authorization (HIGH)

File: app/Http/Controllers/Ajax/ContestController.php:114-132

GET /ajax/contest/downloadPDF allows any authenticated user to download any contest's PDF. No clearance check is performed, unlike other contest admin functions that check judgeClearance($cid, Auth::user()->id) == 3.

4. Contest Account Generation via GET (CSRF + No Max) (HIGH)

File: app/Http/Controllers/Ajax/GroupAdminController.php:17-37

GET /ajax/group/generateContestAccount creates user accounts via GET (no CSRF protection). Unlike ContestAdminController which validates max:100, this endpoint has no upper bound on the num parameter.

5. OAuth Unbind via GET (CSRF) (MEDIUM)

Files: app/Http/Controllers/OAuth/GithubController.php:113-128, OAuth/AAuthController.php:114-126

OAuth unbind endpoints use GET requests for state-changing operations, enabling CSRF attacks that could lock users out of their accounts.

Root Cause

The API endpoints were built without the ownership/share checks that the web Ajax endpoints correctly implement. The api.submission.exist middleware should be extended to verify submission ownership or share status.

Recommended Fix

// In Exist.php middleware, add ownership check:
if ($submission->user_id !== auth()->user()->id && !$submission->share) {
    return response()->json(['success' => false, 'message' => 'Unauthorized']);
}

For the contest PDF, add clearance check matching other admin endpoints.


Found during security research. This report covers vulnerability classes and fixes without providing exploitation details.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions