Read-only, enforced by PostgreSQL

LEDAR never writes to your database. The stronger statement is that it does not rely on itself for that: it asks the database what the role can do and reports the answer, so the guarantee comes from the same system that would have to enforce it anyway.

  • A role the database reports as a superuser is refused. There is no button to proceed anyway.
  • Statement, lock and idle timeouts are set on the connection, because a long-running SELECT can stall a table during a migration even with no write permission.
  • The most the product will ever do about a problem is print SQL for you to run yourself.

Nothing leaves without a permit

There is exactly one outbound network request in the product, and it happens only when you ask a question in plain language and agree to send it. Connecting, scanning, mapping and the interview make no network calls at all.

  • No row values are sent. Table and column names are, and the product treats that as a disclosure rather than as nothing.
  • The screen names the destination, the identifier count, the byte count and the full list of table names, then waits.
  • The permit is hashed over the exact bytes to be sent. Changing one identifier afterwards makes the send fail rather than proceed.
  • A non-HTTPS endpoint that is not on your own machine is refused before your key is attached, and redirects are not followed.
  • Your key is stored through the operating system’s encryption. If the OS cannot encrypt it, storage is refused rather than falling back to a plaintext file.

The permit is a required argument rather than an optional one, which is the part that matters: a place in the code that has not thought about consent does not compile.

Attacks we ran, including the ones that worked

A database schema is attacker-influenced input. A table can be named to read as an instruction, and a question can be written to carry one. We fired 32 prompt-injection attempts at the live question path. 8 of them got through.

What held and what did not
AttackResult
Aiming at a target outside the menu the product builtClosed. The call fails rather than following it.
Aiming at the wrong target inside the menuOpen. A real schema has many legitimate targets, and a wrong-but-valid one is not distinguishable from a right one.
Making the product walk far more routes than the question needsBounded by a query budget, so the consequence is capped. The behaviour itself is not prevented.
Malicious text inside table and column namesNearly inert across 47 runs. The one identifier that was ever picked up did not look like an attack at all.

The one control case that never failed is also the one with the weakest evidence: the model ignored the planted decoy on all four attempts, so the branch that would prove that defence has never actually been exercised on the live path. It is listed here as unproven rather than as passing. The full numbers are on the status page.

What the product refuses to say

Several of the properties above are refusals to speak rather than features, and they are enforced in the contracts the code compiles against.

  • A negative claim without a coverage boundary is rejected, not softened. "Nothing is wrong" is not sayable; "nothing is wrong in the 94 tables I read" is.
  • An observed pattern is never called a bug until you confirm the intent behind it. The product does not know what your business meant.
  • A step that did not happen is reported as not arriving, never as zero.
  • A route that could not be afforded is named, never quietly dropped.