OSAntiCheat

July 17, 2026 · View on GitHub

status: experimental phase: calibration & data-gen version response: log--only license: MIT

Important

Early-stage research project — not production-ready. OSAntiCheat is under active development. Right now we are in a calibration & data-generation phase: detectors are being tuned and validated against real server data, thresholds are not final, and detection axes are still being added and reworked. Expect breaking changes between versions.

Because it is statistical, it flags probabilities, not proof. The current response is log + admin notice only — it never auto-kicks or bans. Do not deploy it as your sole line of defense, and do not act punitively on its output yet. Follow along and star the repo if you want to watch it mature. ⭐

Server-side, heuristic anticheat for CS2, built as a CounterStrikeSharp plugin in C# (.NET 10).

Server-side only — no client component. We observe only what the server sees (positions, view angles, shots, timing) and infer cheating statistically. That means we flag probabilities, not proof — but it's impossible for a cheater to bypass by hiding their client. The v1 response is log + admin notice only, never auto kick/ban.

Detectors (implemented — under calibration)

These detection axes are built and pass unit tests against synthetic tick data, but none are finalized: thresholds are still being tuned against real server data and any axis may be reworked or dropped. Treat the table as what we're testing, not what is proven.

DetectorSignalNotes
SpinbotImpossible sustained yaw rotationSelf-contained; lag-robust (skips sequence gaps)
Aimbot (snap)Large pre-fire view snap that lands on an enemy hurtboxHitbox-agnostic (nearest body part, not the head); lag jumps land on nobody and are ignored
TriggerbotShot fired too fast after the crosshair crosses onto an enemyRepetition-gated; ignores holds, sprays, bots, and enemies walking into a static aim
Wallhack (track)Aim follows a moving unspotted enemy through geometry — the crosshair tracks its bearingUses CS2's spotted system as the LOS signal. Requires the view to follow the movement, so a held angle an enemy crosses is not flagged (fixed after live-data false positives)
Wallhack (gaze)Gaze follows an unspotted enemy's movement — glancing/tracking, not a precise lockView yaw must move in step with the enemy's bearing (not just point in its direction). Round-start window weighted higher (no legit info yet)
Null testCrosshair on an unspotted enemy's present position more often than on its 1.5s-past positionMeasures an information channel, not skill: game sense correlates aim with the past too, so the present-over-past asymmetry isolates present-knowledge-while-unseen = wallhack. Scored as a McNemar z (self-calibrating; skill cancels; no playtime confound) — see below

All signals feed a fusion engine that triangulates independent axes into a per-player suspicion score (graded confidence, exponential decay, corroboration bonus, Watch/Review tiers). No single signal condemns — corroboration across detectors does, and a human reviews.

Calibration (v0.5.0)

wallhack.track's defaults come from a parameter sweep against real demos containing three admin-banned cheaters, each alongside the legit players of their own match — not from guesswork. Measured in signals per alive-minute (score accumulates, so raw score just measures playtime):

rate/min
Banned cheaters (3)0.68 – 1.23
Highest of 133 legit sessions0.21
Best players at their best (three top legit regulars)0.10 / 0.07 / 0.00
Legit median0.00

Zero of 133 legit sessions reached the lowest cheater. Legit baseline is 0.026/min over 1132 minutes — cheaters run 30× that (P(≥5 signals | legit baseline) ≈ 1e-6).

Limits, honestly: the config was selected on those three cheaters, so their numbers are optimistic and the p-value doesn't price in searching 1600 configs. All three likely ran the same cheat, so this shows the detector catches that cheat, not wallhacks in general. Only five cheater signals in total. The legit baseline is the solid half. Replay tooling lives in tools/ — the next banned cheater is a held-out test.

New in v0.6.0 — the null test as a live detector

Replaying 11 demos over the server's own ban list (verified cheaters + their matches' regulars) found the tracking detector fires on the regulars (they are the ones scanning), while the null test — present-position hits minus 1.5s-past-position hits on unspotted enemies — ranked the verified cheaters 1st, 2nd and 8th of 70. It is now a live detector (wallhack.nulltest).

v0.6.1 — scored as a McNemar z-test

Live data exposed two flaws in the raw excess (present-rate − past-rate): it was noisy at low sample counts (early +2–6pp readings were chance, converging to ~0.1–0.5pp), and its accumulated score just re-measured playtime — the whole population drifted to Review on exposure alone. v0.6.1 replaces it with a McNemar test: of the samples where present and past disagree, it forms z = (b − c) / sqrt(b + c) from present-hit-not-past (b) vs past-hit-not-present (c). Skill cancels (concordant hits are ignored), it is self-calibrating (z ≥ 3 ≈ 99.9% the asymmetry is not chance, server-independent), and a player with no real effect stays at z ≈ 0 however long they play — so it no longer confounds playtime. Emission is escalation-gated to one signal per z-band. Config: NullTestMinObservations (30) and NullTestMinZ (3.0). Still log-only.

See TODO.md for the full roadmap, including the wallhack / soft-aim / information- causality detectors planned for later phases (which depend on server-side raycasting and audibility modelling — to be verified first).

Build & release

./scripts/build.sh               # build (Release) + run tests
./scripts/clean.sh               # remove bin/ obj/ dist/
./scripts/release.sh             # -> dist/OSAntiCheat_v<version>.zip

release.sh produces a zip containing a single OSAntiCheat/ folder, ready to extract into .../counterstrikesharp/plugins/. The version comes from <Version> in the csproj; the CounterStrikeSharp API dll is host-provided and intentionally not shipped.

Configuration (thresholds, detector toggles, log path) is generated on first load — see OSAntiCheatConfig. The css_osac_debug in-game command dumps your latest tracked sample to verify the sampler on a live server.

Acknowledgments

OSAntiCheat is server-side and statistical, but several detection concepts trace back to earlier open-source SourceMod anti-cheats. These projects are largely abandoned now; we build on their ideas and credit them where due:

  • SMAC — SourceMod Anti-Cheat — aim-snap-on-kill, spin yaw-velocity gating (with a sensitivity exclusion to spare legit high-sens flicks).
  • Little Anti-Cheat / Lilac — impossible pitch/roll angle bounds, ConVar-query cheats, NoLerp interp math.
  • CoW Anti-Cheat — event-timing checks (e.g. instant-defuse).

Those are Source 1 and built on the per-command usercmd stream. OSAntiCheat reimplements the applicable ideas in C# from per-tick server state for CS2 / Source 2 — concepts only, no code is copied. Where a specific detector adapts an idea, it is cited inline at the detector.

📖 docs/prior-art.md is our open review log of every anti-cheat (and academic project) we studied — what each detected, whether it's reproducible in a server-side statistical model, and an honest verdict on what we could take from it.

License

MIT — see LICENSE.