Product · The attestation

The Sanitisation Attestation, field by field

Every output bundle LogVeil, from Zindagi Technologies, produces is accompanied by a Sanitisation Attestation: a canonical-JSON manifest, signed with the installation's Ed25519 key, that records what was done to the bundle, what was checked, by which scanners, with what result — and what is explicitly not asserted. A standalone command verifies any output against its attestation without the LogVeil server. This page walks through one complete attestation, field by field, with the explanation beside each part.

Everything on this page is a specimen. No real attestation exists yet — LogVeil is in development, and an early-access programme opens after our first field trial. The job, the bundle, the counts and the hashes below are synthetic; the addresses are the documentation range 203.0.113.0/24 and the shared address space of RFC 6598; the site names are placeholders. Field names are illustrative — the attestation schema is published with the full product. What is not illustrative is the list of things an attestation must contain: every field shown is one the product’s specification requires.

Read these first

The non-assertions

in development

Does an attestation mean the output contains nothing sensitive? No. LogVeil does not promise that nothing sensitive remains. It states, in a signed attestation, what was rewritten, what was dropped, what was passed through, which scanners checked the output and what they found, and what is explicitly not asserted. In the vocabulary the attestation itself uses: policy-conformant sanitisation, verified by independent scanners, with declared non-assertions. The non-assertions are mandatory text in every attestation, and they are the part to read first, because they tell the security cell exactly where to look.

SPECIMEN — SYNTHETIC VALUES · the non-assertions — read these first
"non_assertions": [
  "classes outside the policy: S5 location and
   S10 organisational identifiers were not
   enabled in policy example-release v3",
  "encodings outside the enumerated list were
   not searched",
  "binary members passed through unread:
   db-export.bin, core.7712, trace-04.bin",
  "structural inference (S13) not rewritten:
   subnet sizes, host counts, timing, port mix",
  "unknown member formats: 2 members of
   unrecognised type passed through, listed",
  "review overrides: 1 candidate accepted as a
   version string by the reviewer",
  "truncation: none"
]

Classes outside the policy. The customer's policy enables, disables or retargets each of the thirteen sensitivity classes. Whatever it did not enable was not looked for, and the attestation says which.

Encodings outside the enumerated list. Recognisers search a finite, declared list of encodings; the attestation does not claim anything about an encoding outside it.

Binaries passed through, by name. A member that cannot be rewritten and was passed through under the policy is named here — and, by name, in the member list.

Structural inference. Subnet sizes, host counts, timing and port mix are not rewritten; the shape of the network is declared, not hidden.

Unknown formats, review overrides, truncation. Members of unrecognised type; anything a reviewer overrode; and, if a container was truncated or corrupt, how far it was read and how many bytes were not.

The specimen

The specimen, field by field

in development
SPECIMEN — SYNTHETIC VALUES · the job and its time source
{
  "attestation_version": "1",
  "job": {
    "id":       "specimen-fmc-troubleshoot",
    "tenant":   "example-org",
    "created":  "2026-09-05T10:22:41+05:30"
  },
  "time_source": "chrony against the local
                  clock; not externally verified",

Job and tenant. One job is one bundle, one policy version, one output, one attestation. Keys, policies, maps and audit are per tenant.

Time source, declared. An air-gapped clock is unverified, so the attestation says where its time came from rather than pretending to a precision it does not have.

SPECIMEN — SYNTHETIC VALUES · the input and the inventory
  "input": {
    "filename_sha256": "4b7e…c1d2",
    "size_bytes":      1557239808,
    "sha256":          "e3b0…b855",
    "container":       "gzip/tar"
  },
  "inventory": {
    "members": 1284, "nested_archives": 41,
    "max_depth": 5, "manifest_sha256": "0f2a…77e1"
  },

Input hashes and size. The input's SHA-256 is recorded before anything runs. Its filename is content too — it may carry a hostname or a site — so only its hash appears.

Inventory. Every job begins with an inventory of the members discovered — path hash, size, detected type, depth, container chain — before any transform runs. The attestation is checked against that inventory, so a member cannot vanish or appear unrecorded.

SPECIMEN — SYNTHETIC VALUES · the policy, the versions, the key identifier, the output pool
  "policy": {
    "id": "example-release", "version": 3,
    "sha256": "7c1e…a90b", "signed_by": "policy-author"
  },
  "versions": {
    "engine":   "0.9.2",
    "profile":  "[email protected]",
    "recogniser_packs": { "core-network": "1.2.0",
                          "secrets": "1.1.3",
                          "cisco": "1.0.7" },
    "transform_pack":          "1.2.0",
    "residual_leak_catalogue": "1.1.0"
  },
  "key_id":      "tenant-key-example-org-2026-08",
  "output_pool": "100.64.0.0/10",

The policy — identifier, version, hash. The policy is the customer's: versioned, hashed and signed by the customer's policy author. The attestation pins the exact version that governed this job.

Versions of everything that decided the result. The engine, the bundle-family profile, each recogniser pack, the transform pack and the residual-leak catalogue — so a result can be reproduced, and so a later question ("which pack was in use that day?") has an answer.

Key identifier, never the key. The same tenant key gives the same replacement across bundles and across time; the attestation names the key by identifier only.

Output pool. The address space replacements were drawn into — by default the shared address space of RFC 6598 — so a recipient knows that anything in it is a replacement.

SPECIMEN — SYNTHETIC VALUES · the members, one entry each
  "members": [
    { "path_sha256": "5d1c…e0a3", "type": "text/log",
      "depth": 2, "size_bytes": 4194304,
      "action": "rewritten",
      "sha256_before": "aa91…3c07",
      "sha256_after":  "b7f0…19de",
      "substitutions": { "S1": 412, "S4": 37, "S9": 3 } },
    { "path_sha256": "c2b8…44f9",
      "type": "application/x-sqlite3", "depth": 3,
      "size_bytes": 218103808, "action": "dropped",
      "reason": "member action: drop, declare" },
    { "path_sha256": "9e07…b2c4",
      "type": "application/octet-stream", "depth": 3,
      "size_bytes": 7340032,
      "action": "passed-through-binary" },
    { "path_sha256": "1f6d…8ab0", "type": "text/plain",
      "depth": 1, "size_bytes": 1024,
      "action": "passed-through-allowlisted",
      "reason": "version file; per-bundle allowlist" }
    … 1280 further members
  ],

One entry per member, at any depth. The path is hashed, because paths are content. Each entry says what was done: rewritten, with the hash before and after and the count of substitutions per sensitivity class; dropped, with the rule that dropped it — here a database export dropped and declared under the policy’s member actions; passed through as a binary, which is why it also appears in the non-assertions by name; or passed through as allowlisted — a version file the per-bundle allowlist recognised.

Nothing is passed through silently. A member either has a rewrite record, a drop record or a declared pass-through. The before-and-after hashes let anyone confirm that the member in the output is the one the attestation describes.

SPECIMEN — SYNTHETIC VALUES · the scanners, with versions and results
  "scanners": [
    { "name": "engine-rescan", "version": "0.9.2",
      "result": "no hits" },
    { "name": "canary-differential", "version": "0.9.2",
      "encodings_searched": 11, "result": "no hits" },
    { "name": "gitleaks", "version": "8.21.2",
      "result": "no findings" },
    { "name": "detect-secrets", "version": "1.5.0",
      "result": "no findings" },
    { "name": "container-metadata",
      "catalogue": "1.1.0", "result": "no residue" },
    { "name": "binary-classifier",
      "result": "3 members listed" }
  ],

Five scanners, run on the output. Verification is a separate stage with its own code path. The engine's own recognisers re-run on the output; the differential canary scan searches for every original value in every enumerated encoding across every member and every container-metadata field; two independent secret scanners, gitleaks and detect-secrets, run unmodified; the container-metadata scanner checks tar, gzip, zip and capture fields against the residual-leak catalogue; and the binary classifier lists every passed-through binary.

Versions and results, always. A scanner that did not run, or ran with an error, is a failed job: a job with a canary hit, an unresolved review item or a scanner error produces no downloadable output.

SPECIMEN — SYNTHETIC VALUES · the review, the utility checks, truncation, the signature
  "review": { "items": 2, "accepted": 1,
              "overridden": 1, "preserved": 0,
              "operator": "operator-01",
              "reviewer": "reviewer-02" },
  "utility_checks": {
    "structural_diff":       "pass",
    "well_formedness":       "pass",
    "referential_integrity": "pass",
    "look_alike_survival":   "pass"
  },
  "truncation": null,
  "signature": {
    "algorithm": "ed25519",
    "key_id":    "install-key-2026-08",
    "value":     "RW…"
  }
}

Review decisions. Ambiguous hits go to a review queue and are never silently masked or kept; every decision a reviewer took is counted here and appears among the non-assertions where it overrode the engine. Operator and reviewer are recorded.

Utility checks. The output is still worth sending: a structural diff of member counts and sizes, well-formedness of structured files after rewriting, referential integrity — every masked value appears exactly where the original did — and the survival of planted benign look-alikes.

Truncation. Null here; for a truncated or corrupt container, the offset and the unread byte count.

Signature. The canonical JSON is signed with the installation's Ed25519 key, compatible with common signing tools. The signature is over the whole body, so a changed count or a removed non-assertion invalidates it.

Verifying without the server

A standalone command

in development
SPECIMEN — SYNTHETIC VALUES · verifying without the server
$ logveil verify <output-bundle> <attestation>
signature    valid    (install-key-2026-08)
membership   match    (1284 members, 0 missing, 0 extra)
hashes       match    (1284 of 1284)

A standalone command. logveil verify checks an output bundle against its attestation — the signature, the membership, the hashes — without the LogVeil server, on any machine. A security cell can run it before release; an auditor can run it later; the recipient can run it on arrival. The argument form above is a placeholder; the command's own documentation is definitive. A human-readable report renders the same attestation, with the reviewer's decisions, for the case file.

In one phrase

What the attestation is, and is not

in development

The vocabulary the attestation uses

policy-conformant sanitisation, verified by independent scanners, with declared non-assertions.

The attestation is the product's honesty mechanism. Two runs of the same input under the same policy version and key produce byte-identical output and an identical attestation body, so a result can be reproduced and checked. The map from original to replacement is not in the attestation and never leaves the deployment: it is stored encrypted, and a masked value is translated back only one token at a time, with a justification, under a two-person rule, in a hash-chained audit log. Zindagi never sees the policy, the key, the map or the attestation unless the customer chooses to share it. The attestation is not a promise: it says, precisely, what was done, what was checked and what is not asserted — the only honest statement a tool can make about arbitrary input, and a more useful one than a promise, because it tells the reader exactly where to look. The words that assert certainty are absent from the attestation, from the product and from these pages, by design.

How it works, in depth → The policy and the key →

Status, and the next step

LogVeil is in development. An early-access programme opens after our first field trial.

Early access is a free, guided proof-of-concept on your own bundles inside your own network: you choose the bundles, you write the policy with our help, and you keep the key; we hand over the offline kit, run the first jobs with your engineers, and leave you with the attestations.

Request early access