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
BlackdoorNewsDemo Update - v0.11.0
In-game event

Demo Update - v0.11.0

Blackdoor · published 26 Jul 2026, 16:42 UTC

All newsPlayers around this dateRead on Steam

Features

  • Customize your UI layout - ~/.config/layout.cfg (same idea as blackdoor.conf's theme customization) lets you rearrange every pane on screen. Just write "width height content" per line and panels place themselves automatically, left to right, wrapping to a new row as needed - no coordinate math required. Want exact placement instead? Use the precise form (x y width height content) for full manual control. List two or more content types on one line (e.g. mission,network) to merge them into a single tabbed panel. Edits apply live the instant you save the file in-game - no restart needed, and if you make a mistake it tells you exactly what's wrong and keeps your last working layout until you fix it. Prefer a visual editor to hand-writing percentages? There's a drag-and-resize designer at blackdoor.tools/layout that exports a ready-to-paste config.

  • wget/curl can now authenticate - pass -u=<user> -p=<pass> (or the long form --username=<user> --password=<pass>) to fetch a protected page directly, without opening browse first. Unlike browse's login form, credentials passed this way only authorize that one call - they don't grant a session or get remembered, matching real wget behaviour. The usage message and the 403 error both now actually explain this instead of just saying "Forbidden".

  • Quick-run from the editor - Ctrl+Enter while editing a script now saves and runs it immediately, without leaving the editor. The first time you use it, the editor shrinks slightly to make room for a small, still fully-interactive terminal strip below it, so you can watch the output (or type another command) without switching views.

  • A few new things to find - not saying what, or where. Good luck.

  • New top hardware tiers - CPU Mk.V ($12,000, 160 ticks/sec), RAM 12 Slots ($8,000), Storage Drive++ ($2,500, 400 files). For anyone who's capped out the shop and is still sitting on cash.

API Changes

  • New: wget(url) / wget(url, username, password) - scripts can now fetch a web-served page directly, without needing connect() first. Previously there was no scriptable way to read HTTP content at all - download() only works on an authenticated SSH connection's real filesystem, and brute_web() only cracks the login without fetching anything. wget() fills that gap: resolves the target by hostname or IP, walks the web roots, checks the page's protected flag against an existing web session/credentials or the passed username/password, and writes the result to ~/downloads/ same as download(). Returns {success, path, size, local_path, error}.

  • New mission objective type: browse - the mission schema now supports checking that a player has viewed a specific page in the in-game browser. Infrastructure only for now - no missions use it yet, official or otherwise.

  • connect() now returns a user field - the username you ended up authenticated as (if any), without a separate whoami() call. Shows up automatically if you log(conn) too, alongside target, hostname, etc.

  • Reconnecting to the same server no longer stales your old conn - calling connect() again without saving the new result used to make scripts' original conn variable silently invalid, even though nothing was actually disconnected. It's now only treated as stale if the active connection has genuinely moved to a different server - reconnecting to the one you're already on keeps the old conn working.

  • whoami() improvements - it now returns your own local account name when you're not connected to anything, instead of silently returning "" as if inheriting a remote session that doesn't exist (matches how the terminal whoami command already behaves). And whoami(conn) now actually checks the conn you pass it - previously it silently ignored the argument and just returned global auth state regardless of whether that specific connection was still active.

  • Pivot chains are now capped at 5 hops - keeps chaining proxies a real tradeoff instead of something you could stack indefinitely for a one-time noise cost. pivot() now fails past 5, same as it already does if the proxy's already in the chain or a trace is active.

  • New: write_local(path, content) - alias for save(), matching write_file()'s naming for the local side. Handy for testing a script's filtering/formatting locally before writing to a remote file.

  • New: ternary operator - condition ? true_value : false_value, for cutting down on nested if blocks.

  • New list methods: pop() and insert() - list.pop() / list.pop(i) removes and returns the last item (or item i); list.insert(i, val) inserts val at index i, shifting the rest right. Both accept negative indices, same as list[-1]. remove(i) already existed but was never documented anywhere in-game - it's now in the editor's cheatsheet alongside the rest.

Bug Fixes

  • /leave #lounge permanently removed the channel - #lounge isn't a regular NPC channel you can lose access to, it's core infrastructure like #blackdoor. Leaving it erased it from your channel list entirely, and /join #lounge afterward just returned "Unknown channel" - the only way back in was a fresh save load. It's now protected the same way #blackdoor already was.

  • Active IRC channel reset to #blackdoor on every load - loading a save correctly restored whatever channel you were last on, but ~2.5 seconds later the boot sequence unconditionally forced it back to #blackdoor anyway. If you load into #lounge, you now stay in #lounge.

  • Boot sequence stole focus back to the terminal - if you clicked into another pane (or used Ctrl+5 for IRC) while the boot animation was still playing out, it got yanked back to the terminal input the moment boot finished. It now leaves your chosen pane alone.

  • scp uploads to a folder (no filename) silently failed to complete mission drop objectives - scp file.txt user@host:/drops/ (trailing slash) wrote to the literal broken path /drops/ instead of /drops/file.txt, since the destination parsing never stripped the trailing slash before checking whether the target was a directory. Typing the full path with filename already worked correctly - only the folder-only form was affected. Fixed.

  • The default probe.bd script errored out around port 24,000 with "Script exceeded maximum execution limit" - a full 65,535-port scan legitimately needs about four times more execution steps than the old safety limit allowed. Raised the limit with plenty of headroom; a genuinely stuck script still gets caught quickly by the separate CPU-overload safeguard, which doesn't depend on this. Also fixed probe.bd itself only ever scanning up to port 65,534 (an off-by-one in its port range), despite claiming to scan all of them.

  • range() could be asked to build an effectively unbounded list in one shot - unlike a loop body, range() allocates its whole list immediately rather than one step at a time, so an oversized request (an extra typo'd zero, say) could hang or crash the game outright rather than getting caught gracefully. It now errors immediately past 1,000,000 elements - comfortably above any legitimate use (a full port scan needs 65,535).

  • "not connected" errors gave no hint why, even right after a successful connect() - list_files()/download()/crack()/etc. all validate that your conn is still the active connection, but the error never explained why an old one had gone stale. It now says so directly when it's because connect() was called again since without saving the new result.

  • upload() required a shop tool that no longer exists - it was gated behind a tool that got cut before launch because a different feature it was meant to unlock alongside upload() was never built. upload() itself has no dependency on that missing feature and was never meant to be affected - it's unlocked by default now, no purchase needed.

  • Killing a script that had connect()'d to a server left its trace running forever, with no way to stop it - a script owns whatever connection it opens itself, so disconnect (the terminal command) correctly refuses to touch it - that's there so a script can't accidentally hijack your real ssh session. But if you killed the script instead of letting it finish, nothing ever cleaned up its connection either, so the trace just kept ticking with no way to stop it. kill now releases the connection, and disconnect explains what's going on instead of just saying "not connected" if a script is still holding one open.

  • save()/write_local() wrote garbage when given anything but a string - save("out.dat", [0, 1, 2]) wrote the literal text <RefCounted#...> instead of the list's contents, because the fallback conversion was stringifying the interpreter's internal value wrapper instead of the value itself. Non-string values now write the same readable form log() and str() already produce (so that example now writes [0, 1, 2]).



- 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…