Security fixes land on the latest minor release only (the version shown on the project badge and in Cargo.toml); older minor releases receive no security backports and should be upgraded promptly. This page states the policy without version numbers on purpose — a hand-written versions table rots on every release (the audit's own finding); the authoritative "which version is latest" signal is the release feed:
| Release line | Supported |
|---|---|
| latest minor release (see Releases) | ✅ |
| any older minor release | ❌ |
Please do not open a public issue for security vulnerabilities.
Email: security@metalogos.dev
If you do not receive a response within 48 hours, please follow up.
When reporting a vulnerability, please include:
- Description — Clear explanation of the vulnerability
- Impact — What could an attacker achieve?
- Steps to Reproduce — Detailed instructions to trigger the vulnerability
- Proof of Concept — Minimal code or scenario demonstrating the issue
- Affected Versions — Which versions are vulnerable?
- Suggested Fix — If you have one (optional but appreciated)
- Your Contact — How we can reach you for follow-up
| Phase | Timeline |
|---|---|
| Acknowledgment | Within 48 hours |
| Initial Assessment | Within 7 days |
| Fix Development | Within 30 days (critical), 90 days (non-critical) |
| Coordinated Disclosure | After fix is released |
We follow responsible disclosure:
- We acknowledge receipt of your report
- We investigate and develop a fix
- We release the fix and publish a security advisory
- We publicly disclose the vulnerability with full details and credit to the reporter
We publicly credit security researchers who report valid vulnerabilities (unless they prefer to remain anonymous).
The following are in scope for security reports:
- Compiler vulnerabilities (code injection, buffer overflows, etc.)
- Runtime security issues
- Dependency vulnerabilities
- Build system security
- Documentation of security features
The following are out of scope:
- Social engineering attacks
- Physical security
- Third-party services not under our control
- Issues in unsupported versions
- Keep your compiler updated — Always use the latest supported version
- Review dependencies — Audit third-party packages before use
- Follow the principle of least privilege — Run compiled code with minimal permissions
- Use sandboxes — Declare
sandboxblocks to restrict filesystem access and cap iteration limits at runtime - Report suspicious behavior — If you notice unexpected behavior, report it
- Validate all inputs — Never trust external data
- Use memory-safe patterns — Leverage Metalogos's security-by-design features
- Keep dependencies minimal — Reduce attack surface
- Run
mlog audit— Static analysis for secrets, SQL injection, HTML injection, and more (src/audit.rs). Three critical checks (dynamic SQL, secret leaks via env sinks, unsanitized HTML in responses) are also enforced automatically at compile time bymlog run/check/serve— they cannot be bypassed even without an explicitmlog auditrun (Наряд №98). - Regular audits — Periodically review your code for security issues
Metalogos is designed with security as a first-class concern:
- Memory safety by default — Built on Rust's ownership model
- Type safety — Prevents entire classes of bugs at compile time
- Sandboxed execution —
sandboxdeclarations restrict filesystem access to an allowlist, blockexec()calls, and cap loop iterations (10 000 per loop) at runtime - exec() behind explicit flags (Наряд №253, Variant A) —
exec()/exec_argv()are denied by default (EXEC_NOT_PERMITTED): process contexts (mlog run,mlog check, serve top level) requireMETALOGOS_ALLOW_EXEC=1; serve route bodies requireMETALOGOS_SERVE_ALLOW_EXEC=1— a route handler never inherits the process flag (replacement semantics, not AND). Every allowed invocation lands in the subprocess audit log. Internal subprocess calls (exec_restricted— html_render, pdf) take no flag: fixed binary, arguments from code, never from request bodies. - Formal verification support — Integration with proof assistants (planned; formulation last reviewed 2026-09-10 — unchanged, still planned: no verification has been performed, and the wording is kept because it is true, not because it is pretty)
- Static security analysis — Core security invariants (SQL injection, secret leaks, HTML injection) are enforced at compile time; additional advisory checks (hardcoded secrets, sandbox coverage, rate limiting, CSRF, open redirects) are available via
mlog audit
The generative pillars extend the security surface. Reflex (local neural models, ADR-0114) is part of the default build; its sequence layer and the Vision pillar (images, ADR-0122) are feature-gated — vision (which implies candle) and candle are not part of default/full in Cargo.toml [features]. Supply-chain gates apply before any weights are used: MODEL_WEIGHTS_UNSAFE (a Category-A compile error) statically refuses SSRF-class hosts, bare un-pinned .safetensors URLs, and pickle-RCE-class weight formats at vision_fetch_weights, backed at runtime by a default-deny allowlist (MLOG_VISION_WEIGHTS_ALLOWLIST), SSRF resolve-pinning, and SHA-256 pinning; provenance is enforced by VISION_UNSIGNED_EXPORT (LSB watermark + .manifest.json sidecar on every default export). Honest status: Vision weights run PARKED — no production PNG yet (go-no-go №212 + runbook №237: the real-weights run has not been executed, so no production image claim is made).
Since Wave 1 (наряды №322–№328) every value in the language carries a three-component security label (conf, integrity, consent-scope) — ADR-0154. Confidentiality is ordered public < consented < private < poisoned, where poisoned is an absorbing quarantine, not an ordinary level: neither join nor meet cures it (a confirmed-compromised channel — today CanaryLeak — has no legal sinks, and lattice arithmetic cannot launder it). Integrity is ordered untrusted < trusted and dual to confidentiality: mixing data can only lower integrity, combining requirements takes the stronger one. Consent scopes travel with the value and intersect on data combination — a value used in two contexts keeps only the consent both contexts carry.
SINK_CLEARANCEfamily (№325, ADR-0161) — at every call site of a classified sink builtin (the list is read from the №316 SSOT classification, never hand-written), each argument's inferred label must clear the sink. Default clearance ispublic;poisonedclears no sink at all. Specialized scenarios keep their own class names:VOICE_EGRESS_UNCONSENTED(voice egress without a consent scope),UNTRUSTED_EXEC_DECISION/SECRET_TO_EXEC(untrusted or private data drivingexec/exec_argv),SECRET_EGRESS_VCS(private labels intogit_push),SECRET_EGRESS_NETWORK(private-infrastructure destinations),PII_EGRESS_NETWORK/PII_EGRESS_OUTPUT(personal data into network/public outputs),UNTRUSTED_EGRESS_NETWORK,IRREVERSIBLE_NO_GRANT(destructive SQL literals —DROP/DELETE/TRUNCATE/ALTER— indb_execute), plus the inheritedSECRET_LEAK,HTML_INJECTION,TAINT_PERSISTENCEclasses.UNTRUSTED_DECISION(№327) — anti-injection on the integrity axis: data that decides control flow (if/else ifconditions,whileconditions,matchscrutinees) must betrusted. Untrusted data as DATA (carrying it, transforming it, returning it) is legal. The sanctioned paths to a trusted decision: validate before deciding, or one-way redact (hash_onlydestroys the data and restores trust).redact(value, "<policy>")(№326) — the only sanctioned downward move. The policy is a VALUE that names both the transformation and the target confidentiality:hash_only→public(one-way SHA-256 fingerprint — the sanctioned path down),all→public(full masking, legacy ADR-0136),secrets→public(legacy),pii→private,pii_strip→private,truncate→private(conservative — pattern strips can miss data, so they do NOT declassify; the gate keeps blocking their output). Unknown policy words are loud runtime errors; dynamic (non-literal) policies pass the label through — no silent downward moves. Every application is an unconditionalREDACT_APPLIEDaudit event ([REDACT][audit-event]on stderr, aSeverity::Infofinding inmlog audit) — no profile or env toggle can switch them off.- Literal markers (ADR-0161 §3) — string literals carrying personal-data markers (passport/SNILS shapes, confidential wording) or private-infrastructure URL markers are seeded
private, trusted. Sound by conservatism: literals without markers stay bottom, so plain programs keep a zero behavioral delta.
Pre-lattice programs relay user-provided data into outputs as their whole point; cutting them off with no migration path would make the gate a cliff.
- What the profile weakens: ONLY the №325 sink-clearance verdicts become advisory — compilation and execution stay green, and every gate hit is recorded as an audit event (
[SINK_CLEARANCE][audit-event]on stderr + aSeverity::Infofinding inmlog audit). - What it does NOT weaken: every other Category-A gate stays at full strength —
SECRET_LEAK,HTML_INJECTION,UNTRUSTED_DECISION,SQL_DYNAMIC,UNTRUSTED_FRAME,MEDIA_SYNTHETIC_UNMARKED,MODEL_WEIGHTS_UNSAFEand the rest are unchanged, andREDACT_APPLIEDevents remain unconditional. - How long it may stay: it is a bridge, not a residence, and there is no fixed expiry date — the exit criterion is per-program. The profile is removed when every flow that hit the gate is either redacted/annotated to pass the strict gate or demonstrably dead. The audit-event count is the burn-down metric; a program whose event count is stuck at a non-zero value across releases carries standing debt, visible in every audit report (ADR-0161 §3).
The compiler lowers static label knowledge into the bytecode: source-backed bindings carry LabelJoin (the VM seeds runtime labels from the same №316 mapping), and every sink call site carries SinkCheck — the runtime twin of the clearance gate. A runtime violation is a distinct [SINK_CLEARANCE_RUNTIME] error plus an audit-event line. The static gates remain the SSOT of every verdict; the runtime twin exists so any divergence between the two backends is loud, not silent. Label instructions are explicitly outside the JIT-eligible class (bytecode::is_jit_eligible) — when a JIT dispatcher appears it must reject label-bearing functions with a distinct error naming ADR-0156, never skip them silently.
tests/run_leak_suite.rs + examples/leak/ hold 28 negative programs that must not compile (each pinned to its expected failure class via an .error file) and 16 legal positives that must keep compiling and running with pinned output. Since №325 the suite runs in BLOCKING mode: a negative that compiles (or a class mismatch) fails CI. This is the regression fence for every gate above.
This section describes what has landed — no new controls are promised here. The Vision real-weights run remains PARKED (no production PNG; №294 formal No-Go) — the lattice does not change that status. Consent sources (voice egress consent) are Phase 2 (№335) — until then every voice egress is unconsented by default, loud by design. The grant algebra for irreversible operations is Phase 3 (№339, ADR-0155) — until then destructive SQL literals are gated loudly without grants.
References: ADR-0154 (the lattice), ADR-0156 (TW/VM/JIT parity), ADR-0158 (declassify-boundaries booking; the implemented declassify contract lives in ADR-0154 §10), ADR-0161 (sink clearance + the legacy profile). The annotated language contract is REFERENCE.md §2; the full trust-boundary analysis is docs/threat-model.md.
A GitHub Release published after this section landed carries four assets,
attached by .github/workflows/release.yml once the owner publishes the
release: the mlog-linux-x86_64 binary, its CycloneDX 1.5 SBOM
(mlog-linux-x86_64.cdx.json, generated for exactly that binary with the
default feature set), BUILD-INFO.txt (exact rustc/cargo/runner versions)
and SHA256SUMS. GitHub also stores two Sigstore-signed
attestations for the binary: SLSA build provenance, and the SBOM bound to it.
sha256sum -c SHA256SUMS
gh attestation verify mlog-linux-x86_64 --repo ShkodnikAI/Metalogos-
gh attestation verify mlog-linux-x86_64 --repo ShkodnikAI/Metalogos- \
--predicate-type https://cyclonedx.org/bomWhat this proves: the bytes were produced by that workflow, in that
repository, from the tagged commit, and the SBOM lists the dependency tree
that build resolved from Cargo.lock (--locked). What it does not: the build
reproducibility is neither claimed nor verified (the stable toolchain floats;
BUILD-INFO.txt records the one actually used), it links the glibc of the
pinned ubuntu-24.04 runner image, and no human-held signing key is involved — trust
anchors on GitHub's Sigstore integration. Releases published before this
workflow existed (up to v0.27.1) have no assets.
We thank the security researchers and community members who help keep Metalogos secure.
Last updated: 2026-09-16