Security overview

StallionOS, version 1.3, effective October 22, 2026

This document describes the security controls the Platform actually implements today. It is not a statement of what we intend to build. Where a control is planned but not yet operating, it appears in section 10 as a roadmap item and nowhere else. We would rather answer a diligence question with "not yet" than be quoted back a claim we could not support.

We hold no third-party security certification — no SOC 2, no ISO 27001, no completed external penetration test — and we do not claim one. Section 11 describes the review pathway we do offer.


1. Architecture summary — the private-data model

The most important security property of the Platform is architectural rather than procedural: your private deal data is never transmitted to our servers.

The Platform separates a public path from a private path. Public market and government-contract data is processed on our infrastructure. Private deal data — the financials, assumptions, and model outputs for a target company you are underwriting — is entered or uploaded in your browser and computed there.

Computation on private inputs runs client-side in WebAssembly. The validated financial engine is compiled to WebAssembly and executed by a Pyodide runtime that we host ourselves on the Platform's own origin, rather than loading from a third-party CDN. Private inputs, intermediate values, and derived outputs are produced and consumed inside the browser.

This is enforced in three independent places, not asserted once:

  1. Schema shape. The only server-side table that references a private workspace, private_workspace_refs, has no payload, financials, or assumptions column. Its only columns are an opaque client-side reference label, a display name, and timestamps, and no code writes to it today. There is no column for private data to be written into.
  2. Automated tests. A privacy test suite covers, among other checks, outbound-request egress on the private export path, absence of third-party scripts on private surfaces, browser-storage scoping, and the Pyodide loader's origin.
  3. Continuous integration. That suite runs on every push, alongside the full test suite, so a regression fails the build rather than shipping.

A reviewer who wants to confirm this can do so directly: open the browser's network inspector while running a private model and observe that no request carries the inputs. We consider that the strongest form of assurance available for this property, because it does not require trusting us.

2. Data handling — what we hold

We hold account and workspace metadata, and the public-path models you choose to save. Specifically:

  • Account records. Email address, a PBKDF2 hash of your password (never the password itself), display name, account status, and creation, update, and last-login timestamps.
  • Organization records. Firm name and membership, including member role and status.
  • Entitlement records. What your account is licensed to use, and when that expires.
  • Session records. A hash of each active session token, its expiry, and its revocation state.
  • Terms acceptance records. Which version of the Terms of Service your account accepted, and when.
  • Saved public-company models. When you save a model or scenario built on the public path — public market and government-contract data — we store it so you can reopen, organize, and compare it later. We hold the name and labels you give it and the working state needed to reopen it as you left it. Saving is an action you take; nothing is stored until you do.
  • Firm settings and output templates. Your firm profile (firm name, preferred deal types, carried interest and default assumptions), your export formatting, and a dated history of changes to them (who changed them and when, not the values). They are your conventions, not deal data.

The Privacy Policy at the StallionOS Privacy Policy is the authoritative statement of what we collect, why, how long we keep it, and your rights over it. This document addresses controls; that one addresses collection. Where the two touch the same subject, the Privacy Policy governs.

3. Authentication and sessions

Password storage. Passwords are hashed with PBKDF2-HMAC-SHA256 at 600,000 iterations, which follows current OWASP guidance for that algorithm. Each password receives its own random salt. The stored value is self-describing — it records the algorithm, iteration count, and salt alongside the hash — so the iteration count can be raised in future without invalidating existing accounts. Passwords are never stored or logged in readable form.

Session tokens. Sessions use opaque random tokens of 256 bits, generated with the operating system's cryptographic random source. The server stores only a SHA-256 hash of each token, never the token itself, so a read of the session table does not yield usable credentials. Sessions expire after fourteen days and can be revoked explicitly at any time; a revoked or expired session is rejected on every request. We deliberately did not use stateless signed tokens, because those cannot be revoked before expiry.

Session cookies. Session and CSRF cookies are set HttpOnly (not readable by JavaScript), SameSite=Strict (not sent on cross-site requests), and Secure by default (transmitted only over HTTPS).

Brute-force resistance. Failed login attempts are throttled: five failures trigger a fifteen-minute lockout. The deliberate cost of the 600,000-iteration hash also makes offline guessing expensive if a hash were ever exposed.

4. Application security

Cross-site request forgery. All state-changing requests are protected by a double-submit CSRF token: a 256-bit random token is issued in an HttpOnly, SameSite=Strict cookie and must be echoed in the submitted form. Every state-changing endpoint validates it, and a mismatch rejects the request.

Subresource integrity. Every vendored browser asset the Platform loads -- scripts, stylesheets, and the WebAssembly runtime bundle — carries a sha384 subresource-integrity hash computed from the file's bytes at build time. If a served file's bytes do not match the pinned hash, the browser refuses to execute it. An automated test recomputes those hashes from disk and asserts that the rendered pages carry them, so a silently altered asset fails the build.

Content Security Policy. Every rendered page carries a Content Security Policy. On both policy variants, connect-src is restricted to the Platform's own origin, so the browser itself blocks any outbound request to a third-party destination. This is the browser-enforced complement to the architectural claim in section 1: even a hypothetical bug that attempted to transmit private data over the network would be blocked by the policy the page ships with.

Third-party scripts. Private-data surfaces load no third-party scripts. This is asserted by an automated test, not by policy alone.

5. Infrastructure

Transport security. TLS is terminated by our hosting provider; session cookies are Secure-flagged by default.

Hosting. The application deploys to Render on a paid single-instance plan in the United States (Ohio region), with a persistent attached disk; production launch is a current roadmap item (section 10). The instance count is deliberately fixed at one because the datastore is SQLite on a single volume and requires exactly one writer.

Sub-processors. One third party processes data on our behalf:

Sub-processor Purpose Location
Render Application hosting and server infrastructure United States (Ohio)

We will update this list before adding a sub-processor. It does not receive private deal data, because private deal data is never transmitted to our infrastructure at all.

Secrets handling. Credentials for backup storage and backup encryption are supplied to the running application as environment variables and are declared by name only in our deployment configuration. No credential is committed to source control.

Application request logging. Request logging is provided at the platform level by our hosting provider. The application itself does not currently emit an access log; see section 10.

6. Data isolation

Every data query is scoped to the requesting user at the repository layer. All reads and writes pass through a repository module whose documented contract is that every artifact access is constrained by the owning user, and soft-deleted records are excluded. Organization membership is separately checked for active status before an organization-scoped resource is returned.

To be precise about the mechanism: this is application-layer scoping enforced in the data-access code, not database-enforced row-level security. We state it that way deliberately rather than using a term that would imply a database feature we do not use.

Private deal data requires no isolation control at all, because it is never transmitted to a shared system. It remains on the client that produced it.

7. Backups and recovery

We do not yet run scheduled backups of server-held data. Encrypted backup capability (Fernet) is implemented and tested but is not operating; turning it on is a section 10 roadmap item.

The implemented capability works as follows. A consistent snapshot of the database is taken, encrypted with Fernet authenticated encryption using a key supplied only through the environment, and uploaded to Backblaze B2 with an object name marking it as encrypted. The key never leaves the environment and is not committed to source control. The same tooling implements the restore path and a grandfather-father-son retention prune, so backups are both recoverable and bounded in age.

Two things are true and worth stating plainly: the encryption key has not yet been generated, and no scheduled job yet invokes the backup on a recurring basis. Both are section 10 items. We are describing a built and tested capability that is not yet operating in production, and we are not describing it as more than that.

8. Dependency and supply-chain security

Python dependencies. Every Python dependency is pinned to an exact version. There are no floating or range specifiers.

JavaScript dependencies. Every JavaScript dependency is pinned to an exact version, and the lockfile records a cryptographic integrity hash for every installed package. An automated test enforces both properties: it rejects any range specifier and asserts that every non-root lockfile entry carries an integrity value. A loosened pin fails the build.

Vendored browser assets. Browser-side third-party code, including the WebAssembly runtime, is vendored and served from our own origin under subresource-integrity pinning rather than loaded from a third-party CDN. This removes an external party's ability to change executing code after the fact.

9. Change management

Database migrations. Schema changes are applied by a migration runner that records which migrations have run, so re-running is a verifiable no-op. Each migration executes inside an explicit transaction: any error rolls that migration back in full, so a partially applied schema is not a reachable state. The runner refuses to execute a migration whose statement structure it cannot split unambiguously, rather than guessing.

Automated testing. The Platform is covered by more than 9,700 automated tests, including the privacy suite described in section 1 and the dependency and integrity tests described in sections 4 and 8.

Continuous integration. Every push runs the full test suite, the privacy suite, and a byte-level check that the financial engine's reference output is unchanged. Changes that break any of these fail the build.

10. Roadmap

This section is forward-looking. Nothing in it is in production today. It is included because a reviewer is better served by a complete picture than by a document that quietly omits its gaps.

  1. Production launch. The hosting deployment described in section 5 is configured but not yet live. Launch, the production encryption key, and the scheduled backup job land together: the backup capability described in section 7 is built and tested, and what remains is generating the key and scheduling the recurring job at launch.
  2. Application-level access logging. The application does not currently emit its own request log; today this is covered only by our hosting provider's platform logging. Adding application-level logging, with private data excluded by construction, is planned.
  3. Managed database hosting. The Platform is configured to run SQLite on a single instance with a persistent disk. Our SQL is deliberately written to remain portable to PostgreSQL so that a migration to managed database hosting, with the operational durability and failover that brings, does not require rewriting the data layer.
  4. Independent review. We have not commissioned an external penetration test or a SOC 2 examination. We will say so plainly until that changes.

11. Contact and review

For security questions, to request current sub-processor detail for a vendor review, or to report a suspected vulnerability, contact nate@valeor.io.

Architecture review under NDA. We offer prospective and current customers a technical review of the private-data architecture under NDA, including a walk through the client-side execution path and the enforcement points described in section 1. This is an offer of access, not a claim of external validation: no third party has audited the Platform to date, and this document does not present the review pathway as though one had.

If your diligence process requires a completed questionnaire on your own form, we will complete it against this document. Where your form asks about a control we do not have, we will answer that we do not have it.

12. Framework mapping — CAIQ and SIG

Section 11 states that we will complete a diligence questionnaire on your own form against this document. This section makes that concrete: it maps each section above to the Cloud Security Alliance CAIQ v4 domains it answers, so a reviewer can work from their form to the relevant text rather than reading the document end to end.

This section adds no control and makes no new claim. Every row points at a section that already exists; where a domain has no backing section, it is listed below the table as not answered rather than answered thinly. A domain earns a cell only where a section genuinely answers it.

Section CAIQ v4 domains answered
1. Architecture summary AIS, DSP
2. Data handling DSP
3. Authentication and sessions IAM, CEK
4. Application security AIS
5. Infrastructure IVS, DCS, LOG
6. Data isolation IAM, DSP
7. Backups and recovery BCR, CEK
8. Dependency and supply-chain security STA, CCC
9. Change management CCC

Domains this document does not answer. Seven of the seventeen CAIQ v4 domains have no backing section here, and we would rather name them than stretch a section to reach them:

  • A&A — Audit and Assurance. We have commissioned no external audit, penetration test or SOC 2 examination, and we describe no internal audit programme.
  • GRC — Governance, Risk and Compliance. We describe no governance, risk-management or compliance programme. Section 11 offers a contact route and a review under NDA, which is not the same thing.
  • HRS — Human Resources. We describe no personnel security, screening, or security-training programme.
  • IPY — Interoperability and Portability. We describe no data portability or export interface in this document.
  • SEF — Security Incident Management, E-Discovery, and Cloud Forensics. Not covered.
  • TVM — Threat and Vulnerability Management. Section 8 describes dependency pinning. We describe no scanning for known vulnerabilities and no patch-management programme.
  • UEM — Universal Endpoint Management. We describe no endpoint or device-management controls.

SIG and SIG Lite. We do not reproduce the Shared Assessments SIG or SIG Lite structure here. If your process uses one, send us your form and we will complete it against the sections above, on the same terms as any other questionnaire.

Where your form asks about a control we do not have, we will answer that we do not have it.