Security

How we build and verify trustworthy software.

Security philosophy

We build verifiable computing infrastructure. Our security posture reflects that: minimize attack surface, maximize auditability, prove correctness where possible.

Zero dependencies

AIIR has zero runtime dependencies. No supply chain to compromise. The entire codebase is open and auditable — roughly 9,200 lines of core logic.

Content-addressed

Every receipt’s integrity is bound to 6 core fields via SHA-256. Change any core field — type, commit, ai_attestation, provenance, schema, version — and the hash breaks. Non-core fields (timestamp, extensions) are annotation-only.

Adversarial testing

We run structured adversarial rounds against every release: fuzzing, homoglyph injection, path traversal, TOCTOU attacks, and more.

Transparency logs

Sigstore integration provides keyless signing, Fulcio certificates, and Rekor transparency log entries. Non-repudiation without key management.

Threat modeling

AIIR ships with a public THREAT_MODEL.md that covers the full STRIDE/DREAD analysis:

STRIDE Category Coverage
Spoofing Content-addressed hashes + Sigstore identity binding
Tampering SHA-256 integrity + Rekor transparency log
Repudiation Keyless signing with Fulcio certificates
Information Disclosure Receipts contain only commit metadata (no source code)
Denial of Service Zero network calls in default mode
Elevation of Privilege No filesystem writes outside specified output dir

Each threat is scored using DREAD (Damage, Reproducibility, Exploitability, Affected Users, Discoverability) with concrete mitigations and residual risk documented.

Adversarial testing program

Every AIIR release goes through structured adversarial rounds. These are not unit tests — they're attacks. Each round attempts to break a specific security property:

  • Receipt forgery — can an attacker produce a valid-looking receipt for a commit they didn't make?
  • Homoglyph evasion — can Cyrillic/Greek lookalikes bypass declared-signal normalization?
  • Path traversal — can --output escape the intended directory?
  • TOCTOU races — can git state change between read and receipt?
  • JSON injection — can commit messages inject fields into receipt JSON?
  • Large input handling — what happens with 10K-file commits or 1MB messages?
  • Signature stripping — can an attacker remove Sigstore signatures undetected?

Results from each round feed back into the test suite as regression tests. The test suite includes these adversarial scenarios alongside functional and fuzz tests.

Technical details

Numbers you can verify. Every stat below maps to a public CI run or open-source file you can audit yourself.

Test infrastructure

Layer What Count
Unit tests Deterministic functional + edge-case coverage 2214 tests
Fuzz tests Hypothesis property-based testing — random & adversarial inputs 52 fuzz functions · ~53,000 generated inputs per run
MCP protocol tests JSON-RPC message parsing, method dispatch, rate limiting, oversized message rejection 80 tests
Coverage gate CI enforces minimum line coverage on every push 100% threshold

CI pipeline

The latest push to main fans out to 41 public check runs across CI, Quality, Security, CodeQL, ClusterFuzzLite, Sync, Scorecard, and receipt automation. Branch protection requires the 3 rollup gates ci-ok, quality-ok, and security-ok before merge:

Job What it checks
test (×7) Full matrix — Python 3.9–3.13 on Ubuntu + Windows + macOS
fuzz Property-based fuzz tests — pure Python, Ubuntu only
lint actionlint — validates all workflow YAML syntax, inputs, and expressions
coverage Enforces 100% line coverage with --fail-under
package Build wheel, install, smoke-test entry points, verify py.typed
CodeQL GitHub code scanning — detects injection, XSS, path traversal, ReDoS
scorecard OpenSSF Scorecard — supply chain risk auditing (currently 7.6/10)
mutation Mutation testing via mutmut — kills mutants to verify test quality
ClusterFuzzLite Continuous fuzzing — coverage-guided inputs via OSS-Fuzz infrastructure
CBOR round-trip Python ↔ Rust parity — verifies CBOR sidecar determinism across languages
Rust SDK Builds and tests aiir-cbor-verify crate with golden vector conformance
ci-ok Summary gate — required by branch protection, passes only if all preceding jobs succeed

Hardening controls

Defense-in-depth measures across the codebase. Each control maps to a specific threat in the threat model.

Control Threat Implementation
Path traversal prevention Directory escape via --output / --verify resolve() + relative_to(cwd) + TOCTOU re-check after mkdir
Symlink rejection File read/write via symlink Explicit is_symlink() checks on all input paths
Git ref sanitization Command injection via branch names Reject ../, shell metacharacters; -- arg separator
Credential stripping PAT leakage in remote URLs urlparse reconstruction removing credentials, query params, fragments
Homoglyph normalization Declared-signal normalization bypass via Cyrillic/Greek lookalikes NFKC + explicit confusable mapping table
OOM prevention Large diff / message denial of service Streaming SHA-256 (no full diff in memory), 10 MB message cap, 50 MB file cap
Rate limiting (MCP) Subprocess flooding via rapid JSON-RPC calls Sliding-window rate limiter (50 requests / 10s)
Error sanitization Information disclosure via stack traces All exceptions stripped to safe messages before JSON-RPC responses
Atomic file writes Corruption from interrupted writes O_CREAT | O_EXCL + os.replace() for config; O_EXCL for receipts
Subprocess safety Environment variable injection GIT_SAFE_ENV with sanitized PATH, stripped GIT_* vars, 60s timeout

Supply chain

Zero runtime dependencies

AIIR's core has zero pip install dependencies. The entire attack surface is the Python standard library.

Pinned CI actions

All GitHub Actions are pinned to full SHA (not tags). No @v4 — only @sha256:... to prevent tag mutation attacks.

Trusted Publisher

PyPI releases use OIDC Trusted Publisher — no stored API tokens. The GitHub Actions workflow identity is the only credential.

Branch protection

Changes to main require the rollup gates ci-ok, quality-ok, and security-ok to pass. Enforced by GitHub branch protection with admin enforcement enabled.

Responsible disclosure

We welcome security reports. If you find a vulnerability, please report it responsibly. We do not have a bug bounty program yet, but we credit all reporters (with permission) and will work with you on coordinated disclosure.
Channel Details
Email noah@invariantsystems.io
security.txt /.well-known/security.txt (RFC 9116)
GitHub Security Advisories Report via GitHub
Response time Acknowledgment within 24 hours
Disclosure timeline 90-day coordinated disclosure

See SECURITY.md in the AIIR repository for the full policy.

What we don't do

  • No telemetry. AIIR makes zero network calls in default mode. Plausible analytics on this website only (no cookies, GDPR compliant).
  • No source code collection. Receipts contain commit metadata and diff hashes, never source code.
  • No key management burden. Sigstore signing is keyless — uses OIDC identity from your CI provider.
  • No vendor lock-in. Receipts are plain JSON. Export, migrate, or self-host anytime.

Remote environment linking

Closed by default. The public website does not currently expose a live path into a customer or operator machine.

A future environment-linking surface would be a high-risk boundary. We will not open it from the website until the public threat model, authentication design, network-boundary evidence, rollout controls, audit logging, and shutdown path are documented and reviewed.

  • No browser-to-local-machine connection is enabled today.
  • No public control endpoint for a workstation or unpublished managed environment is enabled today.
  • No public firewall or edge-exposure posture is being represented here as sufficient for a live machine-link path.
  • The current public site only provides a request path for early access and planning.

Audit the code yourself

AIIR is Apache 2.0. The entire codebase is one pip install away.

View source → Threat model