Status
SteamPeaks
ChartsSalesUpcomingPatchesNewsCalculator
New on SteamEvery app, DLC and depot the minute Steam creates itAppsEvery app on Steam, newest change firstPackagesSubs and bundles, and what each containsDepotsDepots, manifests and install sizesTagsSteam's user tags and the games under themDevelopers & publishersCompanies and their cataloguesTechnologiesEngines, SDKs and anti-cheat found in the filesChange historyEvery PICS changelist as it lands
SignalsNineteen readings of the whole catalogueCompareAny games side by sideRecordsAll-time peaks and the days they were setReportsWeekly and monthly write-upsAlerts & newsroomWatch a game, get told when it movesSteam statusIs Steam up, right nowWeb API explorerTry the endpoints in the browser
NewsSteam's own announcements and the sales calendarCalculatorWhat a Steam account is worth, and its pile of shame
/
Sign in
/
SteamPeaks
The ultimate resource for Steam data.
ExploreChartsSalesSales and festsUpcomingPatchesNewsRecordsTrendingSignals
DatabaseAppsPackagesDepotsTagsDevelopersTechnologiesChange history
ToolsCalculatorCompareSearchAlertsSteam statusAPI
SiteMethodologyFAQDiscordSupportSign in via Steam
Not affiliated with Valve or Steam. Game names and artwork belong to their owners. All times UTC.
PrivacyCookiesFair useStatus
BlackdoorNewsv1.0.2 - Fixes Round Two & More Bits!
Game update

v1.0.2 - Fixes Round Two & More Bits!

Blackdoor · published 8 Aug 2026, 16:27 UTC · build 24630487

All newsPlayers around this dateRead on Steam

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

More from Blackdoor

Other announcements

All news
Game update13 Sep 2026v1.1.1 - bug fixesBug Fixes · sqli() no longer crashes a script when a target has no configured routes - returns a normal checkable result instead. · Object literals, lists, and function calls can now be written across multiple lines. · ls now shows real file permissions and ownership, matching what download()/upload() actually enforce. · The web API reference's connect() entry now carries the same success-vs-lo…Major update10 Sep 2026v1.1.0 - PersistenceThis is the biggest update Blackdoor's had since launch, and it's less about any one feature than about the world stopping being so still. A server used to be a filing cabinet - it sat there with its files and its users until you did something to it, and nothing happened in between. That's fine for a lot of the game, but it meant every "the system noticed you" moment was fake. This update makes…Game update1 Sep 2026v1.0.6 - workshop and scripting fixesNew · Action link syntax (open a firewall port, view server users, etc. from an HTML page) is now documented right in the Workshop editor when editing an .html file, instead of only existing in an external doc. · A new editor= option in ~/.config/blackdoor.conf (simple or nano) - nano mode adds a real Ctrl+X: prompts "Save modified buffer?" if you've got unsaved changes (Y or N then Enter to co…