Security & integrity issues in the common PKO / Tales of Pirates source

Panda

Chaos Pirates
Developer
Server Owner
Registered
LV
0
 
Joined
May 28, 2026
Messages
29
Reaction score
20
Points
8
Location
Chaos Tower
Website
chaospirates.com
Security & integrity issues in the common PKO / Tales of Pirate source

A heads-up for fellow server operators.

Most of us are running the same widely-distributed server source, which means we also inherit the same long-standing bugs. While going through the files I put together a list of security, duplication, and stability issues that are worth patching on any live server. None of these are hard to fix once you know where to look — sharing them so the whole community can harden up.

Locations are anchored to file/symbol names; exact line numbers vary between forks. I've kept this to "what and where" rather than step-by-step exploits, for obvious reasons.




» Economy / duplication
  • Percentage_Random guaranteed drop — functions.lua. If a rate multiplier pushes the chance above 1.0 before the min(1, …) clamp, the roll always succeeds → guaranteed rare drops.
  • Stall purchase integer overflow — CharStall.cpp. The total is summed in a 32-bit value before the gold check, so a large count wraps it → high-value items for almost nothing.
  • Trade / bank / stall / vault dupe window — item moves happen in memory and only persist at the periodic save; a crash mid-transaction can dupe or delete items.
  • Unguarded currency math — broad lack of overflow checks on price × count / gold / IMP / EXP arithmetic.
  • EXP 32-bit overflow — high-level experience overflows its field; an x64 build does not fix it.

» Remote crash / memory safety
  • HandleTable Resolve() null-deref / UAF — ToGameServer.cpp (map-switch / disconnect). A stale connection handle resolves to null and is dereferenced.
  • Packet-pool exhaustion null-deref — Sender.cpp. Allocation returns null under pressure and is used unchecked.
  • GroupServer KickUser null-deref — GroupServerAppServ.cpp. The "player not found" path dereferences the missing pointer.
  • MoveCity birthpoint null-deref — Character.cpp. GetRandBirthPoint() can return null for an unknown destination and is dereferenced without a check.
  • Uninitialized-record UB — the .bin record loaders bake uninitialized memory into records (e.g. CChaRecord scaling fields); a malformed .bin can also truncate a size_t → int size field.

    » Anti-cheat / client trust
    • No movement-speed or teleport validation — the server trusts client-supplied waypoints → speed-hack / position-teleport.
    • Skill range checked after the effect, not before → out-of-range skill use.
    • No rate-limiting on move / skill / trade / stall — only chat is throttled.
    • Predictable / racy RNG — rand() and Lua math.random() are shared across threads without seeding discipline.

    » Auth / session
    • Non-constant-time password comparison, and no per-account brute-force lockout (only a per-IP login cap).
    • Stuck login_status flag — no watchdog/timeout; a ghost session or double-login race can lock an account out until the flag is cleared.
    • Auto-ban lockout loop — a stuck kick cycle can set the ban flag on a legitimate account.
    • Debug commands leak server state — status/ping-style debug commands can return metrics and locate characters when not gated behind a verified GM check.

    » Data integrity
    • Kitbag checksum failure = total inventory loss — Kitbag.cpp (String2KitbagData). One corrupted inventory blob loses the whole bag and can block login.
    • Blob-stored inventory / bank — no per-item GUID or audit trail, so dupes are undetectable and overflow truncates silently.

    » Long-uptime correctness
    • GetTickCount() 32-bit wrap (~49.7 days) — cooldowns, buffs, and timers misbehave after the counter wraps on long-running worlds.

    » Codebase hygiene
    • No DB-outage handling — a synchronous DB connection with no timeout/circuit-breaker; a dropped database hangs the world.
    • No log rotation/retention in the default logging path → unbounded growth.
    • Aging bundled dependencies — EOL libraries with known CVEs on the legacy build path; unpinned versions.




    Bottom line: most of these are a few lines each — add the missing null checks, clamp the RNG and the currency math, validate movement/skill input server-side, and put bounds on the record loaders. The duplication and economy ones (the first few) are the ones I'd prioritize if you run an open economy.

 
Very nice post, thanks for helping the community and future server owners <3
 
  • Like
Reactions: Panda