mklang platform
Public security document

Security: what is enforced, what is not, and how to report a problem.

This platform holds other people's credentials and runs LLM-driven workflows over their business data. This page states what is guaranteed, what is not, and how to report a problem.

Current posture Managed onboarding is open One production host. No SLA. Restore rehearsed. Reviewed 2026-10-29
01 / enforced properties

The controls we can point at.

Nine invariants are stated in the repository, and each is enforced by code and by named tests. An invariant with no test is an intention.

Invariant What it means in practice
No credential is ever written unencrypted Envelope encryption with a per-tenant data key. If the key encryption key cannot be loaded, the service does not start; there is no fallback or development bypass.
No secret enters an mklang blackboard A step never receives a credential. The connector runtime resolves it at call time, and platform checkpoints are sealed before they reach the database.
An unverified webhook starts nothing HMAC covers the raw body and timestamp. Missing, wrong, expired and unknown signatures receive the same answer.
An absent credential is a denial No configuration makes authentication optional. A route test walks the registered surface so a new endpoint cannot be unprotected by omission.
Cross-tenant reads require two independent failures Application scoping and forced Postgres row-level security both protect tenant data.
Every connector response is external data It is marked before it can reach a judgement, so provenance and control-flow taint can act on it.
Logging is allowlist-based A field a vendor adds tomorrow is redacted by default rather than logged by default.
A data-plane credential is reduced to what that plane can use The control plane renews credentials; a runner makes vendor calls. Refresh tokens and client material used only to obtain the next token stay behind the broker.
An external effect is claimed before the call and confirmed after An ambiguous claim stops the run. Durable execution is at-least-once, so this is what stands between a retry and a second email.

Also enforced: a change is audited in the same database transaction that made it — written afterwards, a trail claims things that never committed.

02 / threat model

What the boundary protects.

The model names both sides of the boundary. Threats outside the boundary are listed below.

In scope

  • Cross-tenant data access. Application scoping, row-level security and per-run compute isolation address the worst failure: one tenant seeing another tenant's data.
  • Credential compromise. Per-tenant keys limit the blast radius, and connection lifecycle states make revocation visible.
  • Prompt injection reaching an effect. External data is tracked structurally; the platform refuses an effect reached through a tainted decision.
  • Hostile workflow content. Signed bundles are verified before execution, including every file in the signed manifest.
  • Resource exhaustion. Tenant quotas bound concurrency, runs and tokens.

Out of scope

  • Compromise of a model provider. That inherited trust is disclosed, not defended against.
  • Compromise of a vendor API a connector calls.
  • A tenant's own users acting within their permissions. Authorization bounds action; the audit trail is the control.
  • Physical and hypervisor security of the hosting provider.
  • Availability guarantees. No service level agreement is offered until one is sold.

Python code runs in an ephemeral container with no host credentials, a bounded lifetime and no network. JavaScript and non-empty network allowlists fail closed because those shapes are not implemented.

03 / data handling

Where information sits.

The platform processes customer workflow data on their instructions. The rows below show where data is stored. Data still reaches the model provider (see below).

Class Where At rest Retention
Credentials Control plane Per-tenant DEK Until revoked; tenant-wide erasure is operational
Step payloads, blackboards, checkpoints Data plane Per-tenant data-plane key No automated expiry today
Run metadata Control plane Database-level No automated expiry today
Execution traces Data plane Per-tenant data-plane key 30 days by default; configurable from 1 to 365 days
Audit events Control plane Database-level Append-only; no automated expiry today

Hosting is in Germany. Backups are verified before they are called good, restoring from them has been rehearsed on a throwaway host, and copies that leave the host are encrypted under a key the host does not hold.

The model provider is a sub-processor: a judgement sends the data it is about to whichever provider that deployment is configured for. A customer supplies the provider connection; it is never step material.

04 / responsible disclosure

Find a problem? Give it a quiet path.

Please test only something that is yours. Do not open a public issue. The live host is not a public test target.

Report privately to info@gianlucamazza.it, with mklang platform security in the subject. Encrypted mail is welcome — ask in the clear first and a key comes back.

Our current commitment
Acknowledgement three business days
Assessment with a severity and a decision ten business days
Remediation, mitigation, or a written rationale communicated with the assessment
Credit if you want it
05 / review us

Evidence before reassurance.

A security review that asks to read the code is one of the two named triggers for publishing it. Ask, and that conversation starts rather than stalls.

Every factual statement on this site names a row in a register that ships beside the content, and each row names its evidence: a test, a decision record, or a phrase that must still appear in the security document this page derives from. The build fails when a statement outlives the thing it rested on.