Technical Annexure
Full code evidence, API endpoints, XPath selectors, and methodology.
1. Methodology & Tools
Passive OSINT only — no active testing
| Source | Tool / Method | Purpose |
| GitHub API | api.github.com/search/repositories, search/code | Locate repos by keyword (coempt, globarena, onmark, cbseevalweb) |
| GitHub API | GET /repos/{owner}/{repo}/commits | Forensic timeline of commits with diffs |
| GitHub API | GET /users/{username} | Profile metadata (location, bio) |
| CRT.sh | crt.sh/?q=%.onmark.co.in | SSL certificate transparency — all issued subdomains |
| Wayback Machine CDX | web.archive.org/cdx/search/cdx?url=cbse.onmark.co.in/* | Archived URLs including Angular JS bundles |
| Wayback Machine | Direct HTTP fetch of archived JS bundles | 1.7 MB main.a2bab24a9332a08b.js from 3 Mar 2026 |
| curl / HTTP headers | Live probes of subdomains | Determine which onmark.co.in instances are live (HTTP status codes) |
| grep / sed / jq | Local analysis of cloned repos and downloaded bundles | Extract API endpoints, XPath selectors, credential patterns |
2. Repository Inventory
Three repos by two Coempt employees
segrgokul (Gokul — QA Engineer, Hyderabad)
| Repo | Language | Size | Commits | First Push | Last Push |
New_Coempt_Automation | Java (Selenium + TestNG) | ~2.8 GB (incl. .git) | 8 | 18 Oct 2025 | 18 Mar 2026 |
KNR_Automation_Coempt | Java (Selenium + TestNG) | ~120 MB | 3 | 18 Oct 2025 | 18 Oct 2025 |
viswanthp (Viswanth — Developer)
| Repo | Language | Size | Commits | First Push |
AP_SBTET_AUDIT | C# (ASP.NET MVC) | ~162 MB | 1 | 27 Dec 2024 |
sarthak-sidhant (Sarthak Sidhant — independent researcher)
| Repo | Contents |
coempt | Investigation writeup + tender documents + screenshots |
New_Coempt_Automation — File Structure
src/main/java/
├── browsers/
│ └── BrowserManager.java # URL routing, WebDriver setup
├── OSM/
│ ├── osm_Login_Page.java # Login flow (OTP bypass)
│ ├── osmMainAssessmentPage.java # Canvas-based marking
│ └── osmLogoutPage.java # Session management
├── osmWebElement/
│ ├── osm_LoginPageXpaths.java # XPath selectors for login
│ └── osmMainAssessmentXpaths.java # XPath selectors for marking
├── pageObjMod/
│ └── OsmPom.java # Page Object Model (Singleton)
├── ocrTextModules/
│ └── Ocr_Text_Extract.java # OCR extraction pipeline
├── rtmnuTRProject/
│ └── PomClass.java # KNR board POM
└── ExcelFolder/ # Test data sheets (credentials)
src/main/resources/
└── config.properties # URLs, credentials, API keys
src/test/java/
└── osm_runner_Exceution/
└── osm_Exceution.java # TestNG runner (Jenkins CI)
3. OTP Bypass — Code Evidence
Source: osm_Login_Page.java
package OSM;
import org.openqa.selenium.*;
import org.openqa.selenium.support.*;
import pageObjMod.OsmPom;
import osmWebElement.osm_LoginPageXpaths;
import java.time.Duration;
import browsers.BrowserManager;
public class osm_Login_Page {
WebDriver driver;
OsmPom pom = OsmPom.getInstanceOsmLoginXP();
public osm_Login_Page(WebDriver driver) {
this.driver = driver;
PageFactory.initElements(driver, this);
}
public void login(String userName, String password,
String schoolID, String dob) {
// Step 1: Fill credentials
pom.userName.sendKeys(userName);
pom.password.sendKeys(password);
pom.schoolNo.sendKeys(schoolID);
pom.dob.sendKeys(dob);
// Step 2: Click "Send OTP"
pom.sendOTP.click();
// Step 3: Wait for OTP field to appear on page
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(30));
wait.until(ExpectedConditions.visibilityOf(pom.otpShown));
// Step 4: OTP is displayed? Just click Login.
// No code reads or enters any OTP value.
if (pom.otpShown.isDisplayed()) {
pom.loginBtn.click();
// Alert appears: "You have successfully logged in the OSM portal"
Alert alert = driver.switchTo().alert();
System.out.println(alert.getText());
alert.accept();
}
}
}
Source: osm_LoginPageXpaths.java — XPath selectors for login page
package osmWebElement;
import org.openqa.selenium.*;
import org.openqa.selenium.support.*;
public class osm_LoginPageXpaths {
// OTP field: a plain text input rendered client-side
@FindBy(xpath = "//div/input[@class='form-input otp-input "
+ "ng-untouched ng-pristine ng-valid']")
public WebElement otpShown;
// Login button
@FindBy(xpath = "//button[contains(text(),'Login')]")
public WebElement loginBtn;
// Send OTP button
@FindBy(xpath = "//button[contains(text(),'Send OTP')]")
public WebElement sendOTP;
// Credential fields
@FindBy(xpath = "//input[@formcontrolname='userName']")
public WebElement userName;
@FindBy(xpath = "//input[@formcontrolname='password']")
public WebElement password;
@FindBy(xpath = "//input[@formcontrolname='schoolNo']")
public WebElement schoolNo;
@FindBy(xpath = "//input[@formcontrolname='dob']")
public WebElement dob;
}
Source: BrowserManager.java — URL routing (switchable by config)
public String urlBasedLogin(String loginName) {
String url = "";
switch (loginName) {
case "osm":
url = "https://cbse.onmark.co.in/cbseevalweb/";
break;
case "sctevt_live_result":
url = "https://sctevtexams.in/sn20Yz";
break;
case "knr_live":
url = "https://knruhs.uonex.in/";
break;
// ... additional board URLs ...
default:
url = "https://cbse.onmark.co.in/cbseevalweb/";
}
return url;
}
Source: config.properties — Board switch & credential patterns
# Switch target board with one config value
# login_name=osm → CBSE
# login_name=sctevt_live_result → SCTEVT Odisha
# login_name=knr_live → KNR
login_name=osm
# Credential patterns (values redacted)
osm_username=*****
osm_password=*****
# Service URLs
osm_url=https://cbse.onmark.co.in/cbseevalweb/
4. Automated Canvas Marking
Source: osmMainAssessmentPage.java — HTML5 canvas interaction
package OSM;
import org.openqa.selenium.*;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.JavascriptExecutor;
public class osmMainAssessmentPage {
WebDriver driver;
JavascriptExecutor js;
// Navigate through scanned answer sheet pages
public void markAnswerSheets() {
List<WebElement> scannedPages = driver.findElements(
By.xpath("//div[contains(@class,'thumbnail')]")
);
for (int i = 0; i < scannedPages.size(); i++) {
scannedPages.get(i).click(); // Load page on canvas
// Interact with marking canvas (HTML5 <canvas>)
WebElement canvas = driver.findElement(
By.id("canvas" + (i + 2))
);
// Right-click to open mark allocation context menu
new Actions(driver).contextClick(canvas).perform();
// Select mark value from context menu items
List<WebElement> menuItems = driver.findElements(
By.xpath("//div[contains(@class,'context-menu')]"
+ "//ul/li")
);
WebElement target = menuItems.get(markValue);
js.executeScript("arguments[0].click();", target);
// Double-click canvas at coordinates to confirm allocation
int x = 150, y = 200;
String leftDblClickScript =
"var evt = new MouseEvent('dblclick', {"
+ "bubbles: true, clientX: " + x + ", clientY: " + y
+ "}); arguments[0].dispatchEvent(evt);";
js.executeScript(leftDblClickScript, canvas, x, y);
}
}
// Submit completed evaluation
public void submitEvaluation() {
WebElement submitBtn = driver.findElement(
By.xpath("//button[contains(text(),'Submit')]")
);
submitBtn.click();
}
}
5. Jenkins CI Scale
Source: osm_Exceution.java — CI-ready test runner
package osm_runner_Exceution;
import org.testng.*;
import org.testng.annotations.*;
public class osm_Exceution {
WebDriver driver;
List<String> methodsToRun;
@Parameters({"TestMethod"})
@BeforeTest
public void beforeTest(@Optional("") String testMethods) {
// Jenkins feeds test methods via -DTestMethod parameter
methodsToRun = Arrays.asList(testMethods.split(","));
}
@Test(priority = 1)
public void loginTest() {
// Credentials from environment variables or Excel
String filePath = System.getenv("Filepath");
String loginName = System.getenv("Project_Login");
String browser = System.getenv("Browser");
osm_Login_Page loginPage = new osm_Login_Page(driver);
loginPage.login(username, password, schoolNo, dob);
}
@Test(priority = 2, dependsOnMethods = "loginTest")
public void markingTest() {
osmMainAssessmentPage marking = new osmMainAssessmentPage(driver);
marking.markAnswerSheets();
marking.submitEvaluation();
}
}
Key observation: The runner uses @Parameters and System.getenv() for credential injection — designed for unattended CI execution. A Jenkins job with an Excel sheet of evaluator credentials can sequentially log in, mark, and submit for each account.
6. Subdomain Inventory (CRT.sh)
Source: crt.sh?q=%.onmark.co.in — queried 29 May 2026
| Subdomain | Identified Institution | HTTP Status | Server |
cbse | CBSE | 200 | nginx |
cbse1 | CBSE (secondary) | 200 | nginx |
cbseosm | CBSE OSM eval portal | 200 (HTTP only) | — |
bcu | Bengaluru Central University | 200 | nginx |
bcuosm | BCU OSM | 200 | nginx |
kswu | Karnataka State Women's University | 200 | nginx |
anu | Acharya Nagarjuna University | Timeout | — |
msu | Manonmaniam Sundaranar University | Timeout | — |
gita | GITA Bhubaneswar | Timeout | — |
jntu | JNTU | Timeout | — |
sctevt | Odisha SCTEVT | Timeout | — |
sbtet | AP SBTET | Timeout | — |
msubaroda | MSU Baroda | — | — |
svu | Sri Venkateswara University | — | — |
punjabiuniversity | Punjabi University | — | — |
| ~15 additional subdomains | Not probed | — |
7. Full API Endpoint List (77 endpoints)
Source: Wayback Machine — main.a2bab24a9332a08b.js (3 Mar 2026)
Extracted via: grep -oP '"OnMarkWinWebAPI/[^"]*"' bundle.js | sort -u
Authentication
OnMarkWinWebAPI/Authenticate/CheckUserIDPassword |
OnMarkWinWebAPI/Authenticate/ForgotPassword |
OnMarkWinWebAPI/Authenticate/QRCodeLogin |
OnMarkWinWebAPI/Authenticate/GetQRCodeLoginStatus |
Evaluation — Core
OnMarkWinWebAPI/Evaluation/GetBookletsForMarking |
OnMarkWinWebAPI/Evaluation/SaveMarks |
OnMarkWinWebAPI/Evaluation/SubmitEvaluation |
OnMarkWinWebAPI/Evaluation/GetBookletImages |
OnMarkWinWebAPI/Evaluation/GetBookletImagesS3 |
OnMarkWinWebAPI/Evaluation/UpdateBookletLocation |
OnMarkWinWebAPI/Evaluation/GetAllQuestions |
OnMarkWinWebAPI/Evaluation/GetQuestionImageS3 |
OnMarkWinWebAPI/Evaluation/UpdateQuestionMark |
Re-evaluation
OnMarkWinWebAPI/ReEvaluation/GetReEvalBookletsForMarking |
OnMarkWinWebAPI/ReEvaluation/SaveReEvalMarks |
OnMarkWinWebAPI/ReEvaluation/SubmitReEval |
OnMarkWinWebAPI/ReEvaluation/GetReEvalBookletImagesS3 |
OnMarkWinWebAPI/ReEvaluation/GetReEvalScannedPages |
Verification
OnMarkWinWebAPI/Verification/GetVerificationBookletsForMarking |
OnMarkWinWebAPI/Verification/SubmitVerification |
Dashboard & Reporting
OnMarkWinWebAPI/Dashboard/GetDashboardData |
OnMarkWinWebAPI/Dashboard/GetEvaluationStatistics |
OnMarkWinWebAPI/Dashboard/GetEvaluatorPerformance |
OnMarkWinWebAPI/Dashboard/GenerateReportPdf |
Face / Photo
OnMarkWinWebAPI/face/GetUserPhoto |
OnMarkWinWebAPI/face/UploadUserPhoto |
Notifications
OnMarkWinWebAPI/Notifications/GetAllNotifications |
OnMarkWinWebAPI/Notifications/DeleteNotifications |
OnMarkWinWebAPI/Notifications/MarkAsRead |
Infrastructure
OnMarkWinWebAPI/Evaluation/TestWebCam |
OnMarkWinWebAPI/Common/GetIPAndMACAddress |
OnMarkWinWebAPI/Common/LogEvaluatorActivity |
77 total endpoints. Full extraction available in archived bundle at zo.pub.
8. OCR/AI Pipeline
Two distinct OCR/AI methods in the automation suite
8a. OCR.space API (Cloud-based)
Source: ocrTextModules/Ocr_Text_Extraction_Using_API_Key.java — used for SCTEVT marksheet text extraction, not CBSE OSM. Shown here because it demonstrates Coempt's broader OCR processing capability.
// From ocrTextModules/Ocr_Text_Extraction_Using_API_Key.java
// Uses cloud OCR.space API with key from config.properties
String url = "https://api.ocr.space/parse/image";
con.setRequestProperty("apikey", apiKey);
String postData =
"language=eng" +
"&isOverlayRequired=true" +
"&isTable=true" +
"&scale=true" +
"&detectOrientation=true" +
"&OCREngine=2";
8b. Google Gemini Vision API — Marksheet Schema Extraction
// From nizamProject/SchemaExtractor.java (commit 392614d, 14 Mar 2026)
// Extracts marking schema from university marksheets using Gemini Vision
String prompt = """
You are analyzing the FIRST PAGE of a university marksheet PDF.
Extract the marking schema, subjects, and grade conversion table.
Return strictly valid JSON:
{
"university_name": "",
"exam_title": "",
"num_subjects": 0,
"total_credit": 0,
"max_marks": 0,
"min_marks": 0,
"subjects": [
{
"sr": 0,
"abbr": "",
"subject_name": "",
"tu": 0,
"ti": 0,
"pu": 0,
"pi": 0,
"tumin": 0,
"pumin": 0,
"total": 0,
"min": 0,
"exmp": 0,
"credit": 0
}
],
"theory_grading": [
{
"grade": "",
"description": "",
"range_min": ,
"range_max": ,
"grade_point":
}
],
"practical_grading": [
{
"grade": "",
"description": "",
"range_min": ,
"range_max": ,
"grade_point":
}
]
}
Rules:
- Extract ALL subjects
- Extract TU, TI, PU, PI marks
- Extract TUmin and PUmin
- Extract TOTAL and MIN marks
- Extract EXMP if present
- Extract CREDIT
- If a value is "-" return null
- Return ONLY JSON
- GRADING RANGES: Use the exact boundary value (e.g., 90) for
'range_max' even if the PDF says '< 90'.
- PRINT THE GRADE VALUE AS IT IS LIKE IF IT HAS 05 IN IT
PRINT 05 AND IF IT HAS 5.5 PRINT 5.5 DONT ROUND IT UP
- Return ONLY valid JSON.
""";
Note: The file was src/main/java/nizamProject/SchemaExtractor.java — first added in commit 392614d. In the current main branch the Gemini prompt still exists but the API key was moved to config.properties. The hardcoded key in the original commit has since been removed from the file on main, but remains accessible in git history. No keys or credentials are disclosed in this post.
8c. Custom PDF Extraction
package rtmnuTRProject;
// Structured extraction from PDF answer sheets
// Used for post-evaluation data processing
9. SBTET Server-Side Source Code (Separate System)
Source: AP_SBTET_AUDIT — ASP.NET MVC — NOT the CBSE portal
This is full server-side code for the AP SBTET instance — included because the shared vendor (Coempt) and identical security patterns are relevant context.
Custom Cryptography — HbCrypt.cs
namespace SBTET.Security {
public class HbCrypt {
// Custom hash implementation (not bcrypt despite the name)
public static string Hash(string input) {
// Uses SHA1 internally — see SHA1.cs
return SHA1.Hash(input + salt);
}
}
}
SHA1.cs — Weak hashing
namespace SBTET.Security {
public class SHA1 {
public static string Hash(string input) {
// System.Security.Cryptography.SHA1
// Note: SHA1 is cryptographically broken (2017)
}
}
}
Controller surface (14 controllers)
Controllers/
├── AccountController.cs # Login, Register, ForgotPassword
├── AdminPanelController.cs # Admin operations
├── HomeController.cs # Dashboard, Index
├── StudentPanelController.cs # Student-facing pages
├── PreExaminationController.cs # Pre-exam management
├── PostExaminationController.cs # Post-exam, results
├── NotificationController.cs # Notification CRUD
├── MasterController.cs # Master data management
├── BillDeskPaymentController.cs # BillDesk payment gateway
├── PaymentController.cs # Payment processing
├── HomeController.cs # PDF report generation
├── ExcelController.cs # Excel import/export
└── ApiController.cs # REST API endpoints
Web.config — Connection strings (RELEASE transform)
<!-- From Web.Release.config (production transform) -->
<connectionStrings>
<add name="SBTETEntities"
connectionString="metadata=res://*/Model.SBTETModel.csdl|...;
provider connection string="
data source=PRODUCTION_DB_SERVER;
initial catalog=SBTET_DB;
user id=PRODUCTION_DB_USER;
password=PRODUCTION_DB_PASSWORD;""
providerName="System.Data.EntityClient" />
</connectionStrings>
Note: The actual connection string values are in the repository. We verified their presence but are not reproducing them.
10. Forensic Timeline with Git SHAs
Source: git log — New_Coempt_Automation
| Date (IST) | SHA | Message | What Changed |
| 18 Oct 2025 | Initial commits — KNR board automation (not CBSE-specific) |
21 Feb 2026 17:04 | 38f38dd | new osm code addtion | First OSM files: osm_Login_Page.java, XPath selectors, OsmPom |
21 Feb 2026 17:30 | ... | Screenshots captured | PNG files from live cbse.onmark.co.in showing portal UI |
24 Feb 2026 11:34 | fd38fb8 | new osm changes | Complete rewrite: Login page, assessment page, all XPaths deleted & recreated. Layout screenshots show completely different UI. |
14 Mar 2026 15:09 | 392614d | OCR API with Gemini prompt | Added Gemini Vision schema-extraction prompt to SchemaExtractor.java |
| 18 Mar 2026 | 5f2b... | osm changes | Final OSM-related commit |
Critical window: CBSE Class 12 exams ran 15 Feb – 4 Mar 2026. Mock eval circular: 25 Feb. The portal rewrite (24 Feb) happened before the mock circular and during the exam window.
11. Angular Bundle Extraction
Source: Wayback Machine capture — 3 Mar 2026
| Parameter | Value |
| URL | https://cbse.onmark.co.in/cbseevalweb/main.a2bab24a9332a08b.js |
| Captured | 3 Mar 2026 13:49:08 UTC (19:19 IST) |
| Size | 1.7 MB |
| Framework | Angular (ngfactory, NgModule patterns) |
| Extraction commands | grep -oP '"OnMarkWinWebAPI/[^"]*"' bundle.js | sort -u |
| Unique endpoints | 77 |
| Routes found | 19 (login, marking, re-evaluation, verification, dashboard, profile, settings, webcam-test, etc.) |
12. Artifact Inventory
All evidence archived at zo.pub
Original Repos (still live on GitHub as of 29 May 2026)
Responsible disclosure note: This annexure documents findings from public sources (GitHub, CRT.sh, Wayback Machine). No API keys, passwords, or specific credentials are reproduced. We have not attempted to access any live evaluation system. All findings were obtained through passive OSINT. All code snippets are from public repositories and are reproduced verbatim (minus credential values) for evidentiary purposes.