Skip to content

Security: davccavalcante/gaptime

SECURITY.md

Security Policy

@takk/gaptime is a stable (1.0.0) library and CLI for bi-temporal knowledge-graph memory. We take security reports seriously and aim to acknowledge each one within two business days.

Supported versions

Each published version follows strict SemVer (see SPEC.md section 11 and .github/RELEASING.md). Only the latest minor of the current major receives security patches; an older major receives critical-CVE fixes for 6 months after the next major lands.

Package Supported
@takk/gaptime current latest dist-tag

Reporting a vulnerability

Do not file public GitHub issues for security problems. Send reports to davcavalcante@proton.me (preferred) or say@takk.ag (Takk relay), with the subject line beginning [SECURITY].

Include, at minimum:

  • Affected version (npm ls @takk/gaptime).
  • Reproduction steps or a minimal proof of concept.
  • Impact assessment (what an attacker can achieve).
  • Any suggested mitigation.

PGP or signed reports are welcome but not required. If you need an out-of-band channel, ask in the first message and we will propose one.

Response process

  1. Acknowledgement within 2 business days.
  2. Triage and severity assignment within 7 days.
  3. Fix targeted for the next release; critical issues ship as an out-of-band patch on the affected minor.
  4. Coordinated disclosure: the reporter is credited in the changelog and advisory unless they request anonymity.

Threat model: in scope

  • Credential handling: there is none, and any appearance of it is a bug. GapTime never handles API keys, by product invariant. The KvLike and bridge interfaces receive ready client objects; any path that causes a connection string, token, or key to be read, stored, logged, or persisted by this package is in scope and treated as a vulnerability.
  • Host hook safety. A throwing or rejecting host hook (Extractor, VectorIndex, GraphStore) must never crash the host process or abort a write half-way, and a fact must always be audited even when a hook fails. Any path where a faulty hook corrupts the store, leaves an unaudited fact, or escapes as an unhandled rejection is in scope.
  • The serve bridge. gaptime serve binds loopback by default and refuses non-loopback hosts without a token; the bearer comparison is constant-time; POST bodies are gated by content type (415) and a 1 MB cap (413); CORS headers are emitted only when both --token and --cors-origin are configured. Tokenless instances additionally validate the Host header as the DNS-rebinding defense: any request whose hostname (port stripped, IPv6 brackets tolerated) is not loopback (localhost, 127.0.0.1, ::1) is answered 403 forbidden host, and /healthz is host-checked too; with a token configured the bearer is the gate and the Host header is not consulted. Any bypass of these gates (auth bypass, timing oracle on the token, body-cap evasion, Host-validation bypass in tokenless mode, CORS leak without the double opt-in) is in scope.
  • State snapshot handling. Snapshots are validated by version (version: 1, rejected otherwise with ERR_STATE_VERSION); an unreadable snapshot is quarantined to a .corrupt-* file rather than overwritten, and the engine degrades to fresh rather than crashing. A crafted snapshot that crashes the engine, escapes the defensive restore, or silently destroys recoverable history is in scope. Path traversal in the file backend write path likewise.
  • Untrusted ingestion, as a documented boundary. assert, ingest, and the authenticated write endpoints trust the operator: fabricated facts skew the store. By design this is the operator trust boundary, the host owns input validation, and the keymeshBridge exists to retract facts from a source whose credential is later distrusted. A path where unauthenticated input reaches a write, or where a write escapes the audit trail, is in scope; skew from a trusted-but-lying feeder within the same trust domain is not.
  • Misuse-resistance of statement keys. FNV-1a 64 statement keys are non-cryptographic, predictable, and collision-constructible, and the package must never use them for authentication, authorization, or integrity decisions. Any internal code path that does is in scope.
  • Supply chain. Tarball contamination, compromised npm scope, or a published artifact whose provenance attestation does not match the source commit.

Out of scope

  • The security of upstream provider APIs and the accuracy of the data you choose to assert.
  • Custody of the facts you assert and your provider credentials before anything reaches GapTime; that is the operator's responsibility (GapTime never receives the credentials at all).
  • Store skew caused by an operator asserting false facts within their own trust domain (see the documented boundary above).
  • Theoretical attacks against FNV-1a as a hash; it is declared non-cryptographic and is never used for security decisions. Report a violation of that rule, not the hash.
  • Denial of service through unbounded inputs to your own embedding application; the serve bridge's own caps are in scope, your application's are yours.

Supply-chain assurances

  • Zero runtime dependencies. The transitive attack surface of the published package is the package itself. Sibling bridges are structural; the optional peers are never imported at runtime.
  • Provenance. Every release is published with npm publish --provenance (SLSA attestation from GitHub Actions). Verify with npm view @takk/gaptime@<version> --json | jq .dist.attestations.
  • Files allowlist. package.json#files enumerates exactly what ships (dist, README.md, LICENSE, NOTICE, CHANGELOG.md, SECURITY.md); nothing else can leak into the tarball. The published artifact carries 58 files.
  • Frozen lockfile. pnpm-lock.yaml is committed, and CI installs with --frozen-lockfile, so builds are reproducible and dependency swaps cannot ride a CI run.
  • Two-step release. A reviewable GitHub Release precedes every npm publish (see .github/RELEASING.md).

There aren't any published security advisories