Online Code Judge and Auto-Grader with a Real Sandbox (Node.js, React, SQLite)
It runs student code in a sandbox it tried to break itself, and it measures what an 'Accepted' verdict is actually worth.
One-time purchase — source code, database, the written report and everything below, all in a single ZIP.
No account needed — pay & download instantly
Look inside the report
Showing the first 12 pages of 72. Tap any page to read it full size — this is the actual Word file you get, not a mock-up.
Screenshots
Tap any screenshot to open it full size. These are from the project actually running — not mockups.
About this project
An online judge in the shape of HackerRank or Codeforces: a student picks a problem, writes code in the browser, submits it, and gets a verdict per test case - Accepted, Wrong Answer, Time Limit Exceeded, Memory Limit Exceeded, Output Limit Exceeded, Runtime Error or Compilation Error. Submissions can be written in JavaScript, Python, C or Java; the judge detects which toolchains are installed and only offers those. The whole UI is React and the whole backend is plain Node - no Express, no ORM, no npm install to run it, and no CDN anywhere.
The part that makes it a project rather than a demo is that it does not trust itself. Student code is never run inside the server process - `vm` is not a jail, and that is a known escape, not an opinion. Every submission runs as a separate process under Node's own permission model, so the filesystem and process spawning are refused by the RUNTIME rather than by our code, with a wall-clock kill, a V8 heap cap and an output cap around it. Then a corpus of fourteen hostile programs is run against it on purpose - infinite loops, memory bombs, output floods, reading system files, spawning shells, opening sockets - and the results are counted rather than claimed.
That corpus found a hole in our own sandbox, which is the reason it exists. Blocking `require('net')` by hooking the module loader looks complete until you notice that Node 22 added `process.getBuiltinModule()`, which hands back a built-in module without going through the loader at all. One line of student code would have had a socket. The study caught it, the wrapper now closes it, and the self-test has a check so it cannot come back.
The second measurement is the one that changes how you read a verdict. When a judge says Accepted, it means the program passed the tests that happened to be written - nothing more. To put a number on that, the correct solution for every problem is mutated one small edit at a time (a `<` becomes `<=`, a `0` becomes a `1`, a `+=` becomes a `-=`), and the suite is scored on how many of those planted mistakes it catches. The visible sample tests catch far fewer than the full hidden suite, and some mutants survive everything - which is a measured statement about what Accepted is worth, from inside the judge itself.
Third: the judge is measured against the correct programs it wrongly rejects. Six programs that compute exactly the right answer, differing only in how they print it - `Yes` instead of `YES`, `62.5` instead of `62.50`, a trailing space, an unsorted tie - are run under three comparators. A byte-exact comparator, which is what most college judges are built with, rejects all six. It also rejects all six of the judge's own reference solutions, because `console.log` adds a newline. That single number is the argument for why the comparator in this project is what it is.
Fourth, the queue is measured against a bound rather than against itself. Judging N submissions on m workers can never finish faster than max(total work / m, longest single job), and that is a proof, not a comparison - so the gap between the measured makespan and that bound says exactly how much scheduling is leaving on the table. Fifth, the same Kadane algorithm is submitted in all four languages and timed, next to a correct-but-quadratic solution that fails on the large tests, to show what a single time limit actually decides.
SQLite is used properly throughout: foreign keys switched ON (they are off by default in SQLite, and the self-test checks it), ON DELETE CASCADE, UNIQUE keys that make a duplicate test index and a double-judged test case impossible, CHECK constraints on roles and limits, and every judgement written in a transaction so half a result can never be stored. Passwords are PBKDF2-SHA256 with a per-user salt and a timing-safe comparison. Sixty-nine self-tests run in front of the examiner, and they need no database, no network and no setup.
Features
- ✓Full judge flow: problem, in-browser editor, submit, per-test verdict
- ✓Seven verdicts, each meaning a different thing - AC, WA, TLE, MLE, OLE, RE, CE
- ✓Four languages - JavaScript, Python, C and Java - detected at startup
- ✓Submissions run in a separate process, never inside the server
- ✓Sandboxed by Node's own permission model, not by our own checks
- ✓Wall-clock kill, V8 heap cap and a 1 MB output cap around it
- ✓14 hostile programs are run against the sandbox on purpose, and counted
- ✓The study found a real hole in our own sandbox - process.getBuiltinModule bypassed the module hook
- ✓That hole is fixed, and a self-test makes sure it stays fixed
- ✓Honest table of what is NOT contained: Python and C have no runtime permission model
- ✓Mutation testing measures how strong the tests are, not just whether they pass
- ✓Sample tests catch far fewer planted bugs than the hidden suite - measured, per problem
- ✓Some mutants survive every test, so 'Accepted' is shown to have a limit
- ✓Six correct-but-differently-printed programs are judged under three comparators
- ✓A byte-exact comparator rejects all six reference solutions too - that is why it is not used
- ✓Float comparison with 1e-6 tolerance, chosen per problem, not globally
- ✓Judge queue with a worker pool and an atomic claim, so two workers cannot take one submission
- ✓Makespan measured against a proven lower bound, so the gap is a number and not a guess
- ✓Measured: going from 2 workers to 4 barely helps - the judge does not scale linearly
- ✓The same algorithm in four languages, timed, next to a correct-but-quadratic solution
- ✓Compile time is measured separately and never counted against the time limit
- ✓Problems generate their own test data from a fixed seed - the ZIP carries no megabytes of test files
- ✓Hidden test output is never shown, so the judge cannot be used to extract answers
- ✓Another student's source is never shown - only the verdict
- ✓SQLite with foreign keys ON (off by default) and ON DELETE CASCADE
- ✓UNIQUE keys make a duplicate test index and a double-judged test impossible
- ✓Every judgement written in a transaction - half a result cannot exist
- ✓PBKDF2-SHA256 passwords with a per-user salt and timing-safe comparison
- ✓HttpOnly, SameSite session cookies; role checks on the server, not just in the UI
- ✓REST API with X-API-Key alongside the browser session
- ✓69 self-tests that run with no database, no network and no setup
- ✓Zero install: the database is built into Node and the React bundle ships built
- ✓No CDN anywhere - the whole thing works with the internet switched off
Modules
Tools
- • Node.js 22 or newer (nothing else is required)
- • React 19 with Vite (the built UI ships inside - no npm install needed to run it)
- • node:sqlite - the database is built into Node, so there is no MySQL and no XAMPP
- • Node's permission model (--permission) for sandboxing
- • Optional: Python 3, gcc and a JDK - each one adds a language students can submit in
- • Any editor and any web browser
Requirements
Node.js version 22 or newer, and nothing else. The database is `node:sqlite`, which is built into Node - there is no MySQL, no XAMPP and no .sql file to import. The React interface ships already built inside the ZIP, so there is no `npm install` and no internet needed to run it. Python 3, gcc and a JDK are OPTIONAL: if they are on your PATH the judge offers those languages too, and if they are not, the judge simply does not list them and everything else works. Tested on Windows; it runs the same on Linux and Mac.
How to run
1. Extract the ZIP. 2. Open CMD and go to the folder: cd path\to\online-code-judge 3. Check everything is ready: node check_setup.js 4. Load the problems and demo submissions: node demo.js 5. Start it: node server.js 6. Open http://127.0.0.1:5000 in your browser. 7. Login: admin / admin123 (students: aditya / student123) demo.js takes about half a minute - it seeds six problems with 63 tests and then actually judges seventeen demo submissions, so the site has real verdicts in it from the first screen. Before a viva run 'node test/run.js' - 69 checks, and they need no database and no network. To regenerate every number used in the report: node evaluation/study.js (about three minutes). To change the React interface you need npm once: cd client && npm install && npm run build. You do not need this to run the project - only to modify the UI.
The same steps are in README.md inside the ZIP, along with a troubleshooting table.
What you get in the ZIP
- 📁 Full source code — commented throughout, so you can explain it in the viva
- 🗄️ Database — the schema builds itself on first run, with sample data
- 📖 README.md — step-by-step run instructions, database design and troubleshooting
- 📄 Full project report (Word) — Written out and formatted for AKTU — not an outline you have to fill in
- 📊 Presentation (PPT) — Ready for the final viva presentation
- 📝 Synopsis (Word) — The short write-up your guide asks for before approval
- ❓ Viva questions with answers — The questions examiners actually ask about this project
- 📐 20 ready-made diagrams — DFD, ER, use case, sequence and architecture, as images you can paste straight into the report