HomeGamesUpdatesPricingMethodology
Steam News8 August 20263d ago

v1.0.2 - Fixes Round Two & More Bits!

New exit() - halts a script immediately, even from inside a function. return only pops back to whatever called that function; exit() stops the whole script right there, at any nesting depth.

In this update3

Full notes

Full Blackdoor update

Read the full published notes in a cleaner layout. The original post stays linked below.

What changed

15 fixes0 additions4 changes1 removal
  • Gameplay
  • Compatibility
  • Performance
  • Server
  • Fixes
  • UI and audio
changedNewget_args() - returns every argument a script was called with, even ones beyond your declared @param list. Previously anything passed past the last @param was silently dropped.
removedChangessqli() and cmd_inject() no longer need a conn argument - they're plain HTTP checks against a web form, same as wget()/browse(), so requiring a connect() session first was never actually necessary. Just call sqli(url) / cmd_inject(url) directly now.
changedChangesFont size setting now goes up to 48pt (was 20pt) - helps on some Linux/HiDPI setups where the terminal was unreadably small even at max size. Past 20pt (the old ceiling) the value gets a red [UNTESTED] tag next to it, since that's genuinely true - the UI has never actually been checked at those sizes. Go wild.
changedChangesVarious performance changes
fixedBug FixesForkbomb (or a script reconnecting to an already-cracked target) could permanently disable tracing on that server - a check meant to make sure trace never gets skipped on your actual mission target was comparing server references directly, which silently stopped matching once that server got reset (by forkbomb, or by abandoning and restarting the mission). Fixed to check by IP instead, which can't go stale the same way.
fixedBug FixesA server could stop showing as CRACKED (and crack() would insist on cracking it again from scratch) after abandoning a mission, forkbombing, or just quitting and coming back - resetting the server's live state didn't touch your actually-remembered password in ~/.ssh/credentials , but nothing was checking that on the way back in. crack(), the network panel's status, and reconnecting now all recognize a password you already have.

Blackdoor changes

changedget_args() - returns every argument a script was called with, even ones beyond your declared @param list. Previously anything passed past the last @param was silently dropped.
removedsqli() and cmd_inject() no longer need a conn argument - they're plain HTTP checks against a web form, same as wget()/browse(), so requiring a connect() session first was never actually necessary. Just call sqli(url) / cmd_inject(url) directly now.
changedFont size setting now goes up to 48pt (was 20pt) - helps on some Linux/HiDPI setups where the terminal was unreadably small even at max size. Past 20pt (the old ceiling) the value gets a red [UNTESTED] tag next to it, since that's genuinely true - the UI has never actually been checked at those sizes. Go wild.
changedVarious performance changes
fixedForkbomb (or a script reconnecting to an already-cracked target) could permanently disable tracing on that server - a check meant to make sure trace never gets skipped on your actual mission target was comparing server references directly, which silently stopped matching once that server got reset (by forkbomb, or by abandoning and restarting the mission). Fixed to check by IP instead, which can't go stale the same way.

New

  • exit() - halts a script immediately, even from inside a function. return only pops back to whatever called that function; exit() stops the whole script right there, at any nesting depth.

  • raise("message") (alias: error()) - same idea, but marks the stop as an actual error instead of a clean finish. No try/except to catch it yet (that's a bigger project), just a clean way to abort on a bad condition instead of deliberately triggering an unrelated error to get the same effect.

  • import(expr) now also works as an expression - var lib = import("x") works now, not just the existing statement form (import(x) as alias). Usable anywhere an expression is valid: a var initializer, a function argument, inline.

  • touch(conn, path) / touch_local(path) - create an empty file if it doesn't already exist, and never overwrite one that does. write_file()/save() can create a missing file too, but they're not a safe substitute - calling either on a file that already exists destructively wipes its content to empty.

  • get_args() - returns every argument a script was called with, even ones beyond your declared @param list. Previously anything passed past the last @param was silently dropped.

  • my_files(path) - now takes an optional path (still defaults to your home directory) and returns the same rich {name, path, type, size} shape list_files() does remotely, so you can walk your own local filesystem recursively the exact same way. read_local() accepts a my_files() entry directly too, same as read_file() does with list_files() entries.

  • The browser now supports a few ways to hand-inject a vulnerable form directly, not just the scripted sqli() route.

Changes

  • sqli() and cmd_inject() no longer need a conn argument - they're plain HTTP checks against a web form, same as wget()/browse(), so requiring a connect() session first was never actually necessary. Just call sqli(url) / cmd_inject(url) directly now.

  • Font size setting now goes up to 48pt (was 20pt) - helps on some Linux/HiDPI setups where the terminal was unreadably small even at max size. Past 20pt (the old ceiling) the value gets a red [UNTESTED] tag next to it, since that's genuinely true - the UI has never actually been checked at those sizes. Go wild.

  • Various performance changes

Bug Fixes

  • Forkbomb (or a script reconnecting to an already-cracked target) could permanently disable tracing on that server - a check meant to make sure trace never gets skipped on your actual mission target was comparing server references directly, which silently stopped matching once that server got reset (by forkbomb, or by abandoning and restarting the mission). Fixed to check by IP instead, which can't go stale the same way.

  • A server could stop showing as CRACKED (and crack() would insist on cracking it again from scratch) after abandoning a mission, forkbombing, or just quitting and coming back - resetting the server's live state didn't touch your actually-remembered password in ~/.ssh/credentials, but nothing was checking that on the way back in. crack(), the network panel's status, and reconnecting now all recognize a password you already have.

  • Paths built with an extra slash (e.g. joining a path that already ends in /) could silently fail to resolve - even though the file existed under its normal path. Fixed at the source, so this can't bite any script, not just the default ones.

  • Some old saves still had ~/docs/api_quickref.txt pointing at a dead web address - a leftover from before launch that never got cleaned up in saves carried over from testing. Fixed for those saves too.

  • Publishing anything to the Steam Workshop failed with "submitItemUpdate failed (result=9)"- the preview image path only worked when run from the editor, not in the actual shipped game. This affected every publish, of every content type - should be properly fixed now.

  • touch/new always created the file on your home PC, even while connected to a remote server - unlike mkdir/mv/cp/rm, which already knew to target whichever server you're connected to. Fixed.

  • write_file() (scripting) didn't trigger mission objective checks the way editing a file interactively already did - a script-based edit could be completely correct and just never register as complete, since nothing ever re-checked. Fixed.

  • Adjusted some mission objectives to be less exact

  • Passing a list_files()/my_files() entry directly into read_file(), write_file(), delete_file(), download(), or read_local() never actually worked - it was reading the entry's bare filename (name) instead of its full path (path), which can't match a real path in any case. Fixed to use path.

  • A custom cracker built on hash_string()/hash_distance() (the "Crack Source" shop tools) could converge on a wrong-but-hash-matching password that failed to actually log in - two different characters could hash to the same value at some security levels, so a from-scratch coordinate-descent cracker had no way to tell it had the wrong one. crack() itself was never affected (it hands back the real stored password on success, not its own guess). Hashing is now collision-free at every security level, so a correctly-written custom cracker always recovers the real password.

  • Buying a hardware upgrade (CPU/RAM/disk/network) while a promo discount was active charged the discounted price and marked it "owned", but never actually applied the upgrade - the discounted purchase path skipped the code that applies the effect entirely. Fixed.

  • mv/cp on a remote server never checked your access list - unlike cat/download/edit/rm, which already do. A cracked low-privilege account could relocate or copy a file straight out of a directory it was never granted access to. Fixed.

  • Declining the quit confirmation ("Return to main menu? (y/n)" -> n) printed "Cancelled" but then also "Unknown command: n", and left the prompt stuck showing a bare > - the cancel branch was missing the same prompt-reset step every other y/n confirmation already has. Fixed.

  • A player's own messages sent from Discord (a linked account) never showed up in #lounge in-game - the dedupe that skips re-showing a message you just sent yourself matched on Steam ID alone, so it also silently ate anything posted from Discord under that same linked account. Fixed.

    Typing @everyone/@here (or a role mention) in #lounge actually pinged the whole Discord server through the game-to-Discord chat mirror. - Mentions now render as plain text on the Discord side instead of resolving. Fixed.

  • #lounge timestamps showed the sender's raw UTC clock instead of your own local time - everyone saw everyone else's messages timestamped an offset off from their own clock. Now converted to your system's local timezone for display.

  • Static

Source

Steam News / 8 August 2026

Open original post

Changelog.gg summarizes and formats this update. How we read updates.