ironcondor is a Rust options-strategy backtester. It handles no real
money and routes no orders. It does, however, parse untrusted input
files (historical CSV / Parquet chain feeds and, on read-back, result
bundles) and is designed to run inside firms' production research and CI
pipelines. A parser that panics, hangs, or exhausts memory on a malformed
input is a denial-of-service vector in that CI, so its security posture is
treated like that of any internal service that parses external bytes.
Status: Implementation has landed — the v0.1 core engine (deterministic replay loop and naive fill model) is in place, with the v0.x roadmap ongoing. This policy is in force; the threat model it summarises is a design commitment (ADR-0007).
Do not open a public issue for a security vulnerability.
Report privately via GitHub Security Advisories —
open a draft advisory
on the repository — or by email to Joaquin Bejar <jb@taunais.com>
with SECURITY in the subject.
Please include:
- the affected version / commit,
- a description of the issue and its impact,
- a minimal reproduction (an input file or bundle that triggers it, where applicable),
- any suggested remediation.
- Acknowledgement within a few business days.
- A fix or a mitigation plan before public disclosure; because
ironcondorsits inside CI infrastructure, parser and bundle-read-back vulnerabilities are fixed privately first, then disclosed. - Credit in the advisory and
CHANGELOG.md, unless you prefer to remain anonymous.
Pre-1.0. During the v0.x series, security fixes land on the latest
released minor and are published to crates.io (and, from v0.4, PyPI). There
is no long-term-support branch before 1.0.
In scope
- A malformed or adversarial input file (crafted CSV / Parquet, or a hostile result bundle handed back for read-back) that causes a panic, hang, unbounded memory growth, or a path escape.
- A supply-chain issue: a vulnerable, malicious, or typo-squatted dependency reaching a release.
- Secret leakage: a credential (e.g. an OptionChain-Simulator auth token) written to a bundle, a manifest, a log, or an error message.
- A panic crossing the PyO3 boundary into a host Python interpreter.
Out of scope
- Real-money / order-routing attacks — there is no live execution surface.
- A Byzantine OptionChain-Simulator server (treated as a same-trust data source; its responses are still validated at materialisation).
- OS-level isolation, multi-tenancy, or a hostile host — the deploying firm's responsibility.
- Timing / side-channel attacks — the crate holds no long-lived secrets on its hot paths.
- Every untrusted input is validated once at its boundary, with a resource ceiling and a typed error — never a panic. The immutable, hash-pinned, strictly-validated tape is the model (docs/03 §6.1).
cargo audit+cargo denyin CI from v0.1;Cargo.lockcommitted and itssha256recorded in every bundle manifest as build provenance.#![forbid(unsafe_code)]in the crate itself (PyO3 macro glue is the only tolerated exception, never hand-written).- No panic crosses the PyO3 FFI boundary — every binding maps a typed error to a Python exception.
- Fuzz targets for the CSV / Parquet / bundle-read-back parsers land before v1.0.
- Secrets never reach a bundle, manifest, log, or error — the sole
credential channel is the optional simulator client, and a credential
embedded as URL userinfo (
http://user:token@host) is redacted at serialisation before any recorded copy (the manifestdata_source, the nestedconfig.data_source, or therun_idpreimage) is written; the manifest records only the data-source identity (host URL + tapesha256). Proven by the captured-log credential test.
v1.0 posture affirmation. At the 1.0 cut the three security legs are in
place and verified fresh: untrusted-input hardening with fuzz targets over the
CSV / Parquet / bundle parsers (no panic, hang, or OOM on malformed bytes);
secrets non-leakage (the captured-log credential test above); and the
supply-chain / host-integrity controls — cargo audit and
cargo deny --all-features check both green, suppressing only the documented
RUSTSEC-2024-0436 (paste unmaintained, a notice not a vulnerability, mirrored
in .cargo/audit.toml and deny.toml), with #![forbid(unsafe_code)] intact
and the no-panic-across-FFI control asserted by the Python test suite.
The full threat model, untrusted-input hardening table, and secrets-handling rules live in docs/07-performance-and-security.md.