CVE-2025-67259
Executive Summary
CVE-2025-67259 is a Broken Access Control vulnerability in ClassroomIO v0.1.13. An authenticated low-privileged "student" user can escalate their privileges by manipulating HTTP methods in API requests. By changing a captured POST request to a GET request against the /rest/v1/course PostgREST endpoint, the attacker gains unauthorized access to sensitive course-level information, including other students' details, tutor/admin profiles, and internal course metadata. This vulnerability has a CVSS score of 6.5 (Medium) and currently has no known patch.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Supply Chain & Package Security
ClassroomIO is a self-hosted or cloud-based educational platform. The vulnerability resides in the PostgREST API layer, which is a RESTful API server directly tied to the PostgreSQL database. Since the application is not distributed via NPM, PyPI, Go, or Ruby, supply chain risks are limited to the integrity of the ClassroomIO source code repository and any third-party dependencies used in the backend (e.g., PostgREST itself). Users should verify the integrity of their ClassroomIO installation and monitor for any unofficial patches or forks.
CVSS Breakdown & Threat Level
- CVSS Score: 6.5 (Medium)
- Vector: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N
- Attack Vector: Network
- Attack Complexity: Low
- Privileges Required: Low (authenticated student)
- User Interaction: None
- Scope: Unchanged
- Confidentiality Impact: High
- Integrity Impact: None
- Availability Impact: None
Threat Level: Medium. The vulnerability allows information disclosure but does not enable data modification or denial of service. However, the exposed data (student details, tutor/admin profiles, internal metadata) can be leveraged for further social engineering or targeted attacks.
Deep Dive & Mechanics
The vulnerability stems from improper authorization checks in the PostgREST API endpoint /rest/v1/course. PostgREST automatically generates RESTful endpoints from database tables and views. In ClassroomIO v0.1.13, the endpoint is configured to allow POST requests for creating course records, but the GET method is not properly restricted to authorized roles.
Root Cause: The application relies on HTTP method-based access control without verifying the user's role for read operations. When a student user sends a POST request to create a course, the server correctly validates the user's role. However, if the same authenticated session is used to send a GET request to the same endpoint, the server fails to enforce role-based access control, returning all course records and associated user data.
Attack Flow:
- Authenticate as a student user.
- Capture a legitimate POST request to
/rest/v1/course(e.g., using Burp Suite or a proxy). - Modify the request: change the HTTP method from POST to GET.
- Send the modified request.
- The server returns a JSON response containing all courses, including sensitive user data (student names, emails, tutor/admin profiles, internal metadata).
PostgREST Role Mapping: PostgREST uses database roles to control access. The vulnerability suggests that the student database role has been granted SELECT permissions on the course view or table, or that the authenticator role is misconfigured to allow anonymous reads.
Vulnerable vs. Patched Code
Since no official patch is available, the following comparison is based on expected secure implementation.
Vulnerable Code (Conceptual):
// ClassroomIO backend (Node.js/Express)
app.post('/rest/v1/course', authenticate, authorize('student'), (req, res) => {
// Create course logic
});
app.get('/rest/v1/course', authenticate, (req, res) => {
// Missing authorization check - returns all courses
db.query('SELECT * FROM course', (err, results) => {
res.json(results);
});
});
Patched Code (Conceptual):
app.get('/rest/v1/course', authenticate, authorize('admin', 'tutor'), (req, res) => {
// Only admins and tutors can list all courses
db.query('SELECT * FROM course', (err, results) => {
res.json(results);
});
});
// For students, provide a filtered endpoint
app.get('/rest/v1/my-courses', authenticate, authorize('student'), (req, res) => {
db.query('SELECT * FROM course WHERE student_id = ?', [req.user.id], (err, results) => {
res.json(results);
});
});
PostgREST Configuration Fix:
-- Revoke SELECT on course table from student role
REVOKE SELECT ON api.course FROM student;
-- Grant SELECT only on a restricted view
GRANT SELECT ON api.my_courses TO student;
Exploitation & Lab Setup
Red Team
Prerequisites:
- Burp Suite or any HTTP proxy (e.g., mitmproxy)
- Valid student credentials for ClassroomIO v0.1.13
- Target URL:
https://target-classroomio-instance.com
Exploitation Steps:
Intercept a POST request:
- Log in as a student.
- Perform any action that triggers a POST to
/rest/v1/course(e.g., creating a course). - Capture the request in Burp Suite.
Modify the request:
- Change the HTTP method from
POSTtoGET. - Remove any request body (if present).
- Ensure the
Authorizationheader (e.g., JWT token) remains intact.
- Change the HTTP method from
Send the modified request:
- Forward the request in Burp Suite.
- Observe the response containing all course data.
Example cURL command:
curl -X GET 'https://target-classroomio-instance.com/rest/v1/course' \
-H 'Authorization: Bearer <student_jwt_token>' \
-H 'Content-Type: application/json'
Expected Response:
[
{
"id": 1,
"title": "Math 101",
"tutor": { "name": "Dr. Smith", "email": "smith@example.com" },
"students": [
{ "name": "Alice", "email": "alice@example.com" },
{ "name": "Bob", "email": "bob@example.com" }
],
"metadata": { "created_at": "2025-01-01T00:00:00Z" }
}
]
Blue Team
Detection Steps:
- Monitor API logs: Look for GET requests to
/rest/v1/coursefrom student users. - Alert on method manipulation: Detect when a user who typically sends POST requests suddenly sends GET requests to the same endpoint.
- Review database query logs: Identify unexpected SELECT queries on the
coursetable from student database roles.
Hunting Query (Splunk):
index=api_logs endpoint="/rest/v1/course" method=GET user_role=student
| stats count by user, src_ip, _time
| where count > 1
Indicators of Compromise (IOCs)
- Network IOCs:
- GET requests to
/rest/v1/coursewith a student JWT token. - Unusually large JSON responses from
/rest/v1/course(indicating full data dump).
- GET requests to
- Log IOCs:
- API access logs showing
method=GETandrole=studentfor/rest/v1/course. - Database query logs showing
SELECT * FROM courseexecuted by thestudentrole.
- API access logs showing
- File IOCs:
- No file-based IOCs as this is a server-side vulnerability.
Detection Engineering
YARA Rule
rule Detect_ClassroomIO_AccessControl_Bypass {
meta:
description = "Detects HTTP GET requests to /rest/v1/course from student users"
author = "Valters IT"
date = "2025-04-01"
cve = "CVE-2025-67259"
strings:
$method = "GET"
$endpoint = "/rest/v1/course"
$role = "student"
condition:
$method at 0 and $endpoint and $role
}
Sigma Rule
title: ClassroomIO Broken Access Control - GET Request to Course Endpoint
id: 12345678-1234-1234-1234-123456789abc
status: experimental
description: Detects GET requests to /rest/v1/course from student users, indicating potential access control bypass.
author: Valters IT
date: 2025-04-01
logsource:
category: webserver
product: apache
detection:
selection:
cs-method: 'GET'
cs-uri-stem: '/rest/v1/course'
cs-username|contains: 'student'
condition: selection
falsepositives:
- Legitimate admin/tutor GET requests (filter by role)
level: high
Suricata Rule
alert http any any -> any any (msg:"CVE-2025-67259 ClassroomIO Broken Access Control - Student GET Request"; flow:to_server; http.method; content:"GET"; http.uri; content:"/rest/v1/course"; http.user_agent; content:"student"; classtype:attempted-recon; sid:1000001; rev:1;)
Remediation & Mitigation
Immediate Mitigation:
- Restrict PostgREST permissions: Revoke SELECT on the
coursetable from thestudentdatabase role. - Implement API gateway rules: Block GET requests to
/rest/v1/coursefrom student roles at the reverse proxy level (e.g., Nginx, Apache). - Monitor and alert: Enable logging and alerting for anomalous API access patterns.
Long-term Fix:
- Apply proper role-based access control: Ensure all API endpoints validate user roles for both read and write operations.
- Update PostgREST configuration: Use row-level security (RLS) in PostgreSQL to restrict data access based on user roles.
- Patch or upgrade: Monitor ClassroomIO for an official patch. If unavailable, consider forking the repository and applying the fix manually.
Nginx Rule Example:
location /rest/v1/course {
if ($http_authorization ~* "student") {
return 403;
}
proxy_pass http://backend;
}
Valters IT
Securing Digital Frontiers
{/* [Security Hash: B2A80E04DCAA45BEECCD2A43] */}