Security model
What this application does with your secrets, what it deliberately refuses to do, and — the part most pages like this leave out — what it cannot protect you against.
Where secrets live#
The vault encrypts each account's authenticator secrets, any available revocation code, saved Steam session token and proxy settings on your machine. The authenticator service does not upload these to an ODA backend; we operate no ODA account system or vault-sync service.
The vault is not the only secret-bearing file. Local recovery data and backups also use encrypted envelopes:
- A recovery file per account, created during enrollment or transfer. If writing it fails, ODA reports that recovery still needs attention. It remains after local account removal and needs the passphrase in use when it was written; changing the vault passphrase does not rewrite existing standalone recovery files.
- The previous version of the vault, kept as a backup so a failed write can often be recovered. This is on the same disk and does not protect against disk loss.
- Operation and write-recovery records can retain encrypted secrets or encrypted key material after an interrupted enrollment, transfer or passphrase change. Keep the whole app-data directory when backing up or recovering an interrupted operation; resolve its warning before deleting records.
And one file it does not protect: the maFile you imported from. Import reads those and leaves them exactly where they were — deleting somebody's only copy of a secret would be the worse mistake — so if it was plaintext before, it still is. Moving it somewhere safe is yours to do, and the app says so after every import.
- Key derivation
-
scrypt, deliberately tuned to take a noticeable moment on ordinary hardware.
That cost is the point: it is paid once when you unlock, and paid again by
anyone making offline passphrase guesses. A weak passphrase can still be found.
The current
defaults are
N=131072,r=8,p=1, which uses approximately 128 MiB for scrypt's main memory array per attempt, plus overhead, with a 32-byte random salt and a 256-bit derived key. Every vault records the parameters it was written with, so an old file still opens after the defaults are raised. Stated exactly rather than described, because "tuned to take a moment" is not something anybody can check. These values are in src/shared/vault-format.ts and are the numbers the application actually uses. - Encryption
- AES-256-GCM, with a 12-byte (96-bit) nonce generated fresh for every write. The authentication tag covers the encrypted contents, vault version, key derivation parameters and nonce. Changing those without the key causes validation or decryption to fail. The envelope's informational modification timestamp is not authenticated; it is not proof that a file is the newest copy.
- Writing
- Every save is written to a temporary file, flushed to disk, and renamed over the target, with recovery handling for interrupted replacements. This reduces the risk of partial saves; disk failure, filesystem behavior and failed flushes can still prevent durable storage. The previous version is kept as a backup.
- Locking
- The vault locks on idle and on demand. ODA zeroes its live key buffer and drops the unlocked state. This is best-effort cleanup: JavaScript strings, runtime copies, swap or crash dumps cannot be guaranteed erased. Unlocking requires the passphrase again — being logged in to the computer is not treated as being present at it.
How the application is put together#
- Stored authenticator secrets have a narrow display boundary. The window is a sandboxed renderer with no Node access and no direct filesystem access. Ordinarily it receives generated codes — which change on a thirty-second cycle and do not reveal the secret that made them — and never the secrets themselves. The exceptions are both revocation codes you deliberately asked to see: the backup ceremony, which makes you re-enter your passphrase first, and the end of a transfer, where Steam has just issued a new code and you must write it down. Each is shown once and cleared when you navigate away. Shared and identity secrets are not returned to that interface. The interface does receive passwords and passphrases you type, so a compromised interface is still dangerous. Browser sessions are a separate boundary below.
- A closed list of permitted messages. The interface can ask the privileged part of the application for a fixed set of named operations, each with a validated shape. There is no general-purpose bridge.
- No remote content in the interface. A strict content security policy with no remote origins, and navigation locked to the application's own files. This blocks direct remote loading and network requests from the authenticator interface. It is a defense layer, not a guarantee that a compromised renderer cannot misuse an allowed operation.
- The in-app browser is the deliberate exception: its web pages have no vault API access and can load external resources. The browser holds login cookies scoped to Steam domains so Steam pages open signed in; those cookies are not sent to arbitrary third-party sites. The selected browser route determines which traffic uses the account's proxy; Steam-only mode permits specified third-party sites to connect directly. The routed in-app browser is available in GitHub 1.5.1 and Microsoft Store 1.5.1.
- Developer tools are disabled in release builds, together with the menu accelerator that opens them. "Open the console and paste this to fix your codes" is an attack that works on real people.
-
7 direct dependencies, 41
packages in total. Every package that ships is a package someone
could compromise, so there are as close to none as the job allows — but the
number worth trusting is the second one, because a dependency's own
dependencies ship too. This page used to give only the first, which is a
count of names typed into
package.jsonrather than of packages in the installer. Both are counted when the page is built, the first frompackage.jsonand the second frompackage-lock.json, because a claim that has to be remembered is one that eventually goes stale. The complete list, with versions, is published as an SBOM beside every release, and the Electron runtime is shipped alongside them.
Check these claims against the release#
A security page is only useful when its claims lead back to something a reader can inspect. These links are pinned to v1.5.1, the latest published GitHub release, rather than a future source version or the moving main branch. Compare that version with the copy you run; the download page lists each channel's published version.
- Vault format and encryption
- Parameters and authenticated metadata, encryption and decryption, and the regression tests.
- Renderer and message boundary
- Window isolation and navigation policy, the deliberately narrow preload bridge, and the posture tests.
- Network destinations
- The interface security policy, Steam transport egress enforcement, and tests for allowed and refused routes.
- Deliberate refusals
- The notification-only update check, the fixed confirmation allowlist, and the policy tests.
Deliberate refusals#
- No self-updating. The application checks whether a newer version exists and links to it when the optional direct-build check is enabled. It never downloads or executes an update. Store updates are handled by Microsoft Store.
- Automatic confirmation has a fixed type allowlist. It can act on market listings and trades. Account recovery confirmations are held back and reported to you, and no setting exists to widen the list.
- Revealing a stored revocation code through the backup screen requires the passphrase again, even with the vault already unlocked. The new code displayed at the end of a transfer is the separate exception described above.
- Removing an account requires an explicit acknowledgement, because forgetting an account locally does not remove the authenticator from Steam, and the two get confused with expensive results.
The honest caveat about automatic confirmation#
Automatic confirmation can approve the sale of eligible items. On a compromised account, that can help an attacker turn items into Wallet funds and spend the balance. The incident-response guide explains pending transactions, completed Market sales and the separate CS2 Trade Protection rules.
The confirmation service only confirms what Steam is already asking about; it does not create listings. A user can still create listings on Steam pages in the separate browser. But if something else with access to your account can raise one — a stolen session or an authorised trading tool — then leaving automatic confirmation on for market listings means this application will approve it without showing you.
So: it is off unless you turn it on, it is set per account rather than globally, and it is worth turning on only for accounts where the convenience is worth that trade. If you are not listing in volume, leave it off and confirm by hand. The Activity screen records confirmation actions and outcomes; it is not a replacement for Steam's transaction history.
What this cannot protect you from#
These limits apply even when the checksum and provenance checks pass.
- A compromised computer. Malware running as you, while the vault is unlocked, may read secrets or intercept your next passphrase. Full-disk encryption helps with a lost powered-off device; it does not stop malware running in your session.
- A weak passphrase. scrypt raises the cost of guessing; it does not make a six-character passphrase safe.
- You approving a malicious trade. The application shows you what Steam said and does what you tell it. It cannot know that the person on the other end is not your friend.
- Phishing. No software prevents someone typing their passphrase into a convincing copy of it. Verify downloads, check Steam hostnames and review sign-in and transaction requests before approving.
Reporting a vulnerability#
Report security issues privately. Use GitHub private vulnerability reporting, which is preferred, or email — the address is in security.txt rather than on this page, as a standard discovery location. That file is public and can be scraped. What we commit to is written down: acknowledgement in 72 hours, an assessment in 7 days, a fix or a dated plan in 30 for a confirmed high or critical.