Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ jobs:
- name: Run checks
run: make check

- name: Run security checks
run: make security-check

- name: Run vulnerability check
uses: golang/govulncheck-action@v1
with:
Expand Down
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.PHONY: dev build fmt check-fmt test vet check clean
.PHONY: dev build fmt check-fmt test vet security-check check clean

dev:
mkdir -p ./tmp
Expand All @@ -23,6 +23,10 @@ test:
vet:
go vet ./...

security-check:
go test -cover ./internal/crypto ./internal/security ./internal/userpresence
go run golang.org/x/vuln/cmd/govulncheck@v1.5.0 ./...

check: check-fmt test vet

clean:
Expand Down
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,22 @@ be committed to git. Private device keys are stored outside the repository in
the platform's native secret store when available, or in a restrictive
file-backed identity store otherwise.

## Security Status

Ghostable is beta security software and has not completed an external security
audit. The repository includes a public [security policy](SECURITY.md), a
[threat model](docs/security/threat-model.md), and stable
[test vectors](docs/security/test-vectors.md) so developers can inspect the
claims and reproduce the critical cryptographic checks.

In Ghostable, "zero-knowledge" has a narrow product meaning: plaintext secret
values are encrypted locally before Ghostable writes repository-backed state.
Ghostable does not run a hosted service that receives plaintext project secrets.
This does not mean the local machine, local device identity, shell history,
plaintext `.env` files, deploy providers, or everyone with repository write
access are automatically trusted or harmless. Review `.ghostable/` changes with
the same care as code changes.

## Install

Install Ghostable once, then run it inside each project you want to manage.
Expand Down
24 changes: 24 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,28 @@ and are intended to be committed to git. Private device keys are stored outside
the repository in the platform's native secret store when available, or in a
restrictive file-backed identity store otherwise.

## Security Status

Ghostable is beta software and has not completed an external security audit.
The current assurance evidence is repository-visible: focused security tests,
documented test vectors, and the public threat model in
`docs/security/threat-model.md`. Do not treat the current release as formally
audited or certified.

The zero-knowledge claim is scoped to Ghostable's local-first storage model:
Ghostable does not run a hosted service that receives plaintext project secret
values, and committed Ghostable value records are encrypted locally before they
are written. The claim does not cover a compromised local device, plaintext
`.env` files created for local or deploy workflows, shell history, terminal
logs, third-party deploy providers, CI systems that receive decrypted values, or
malicious repository changes that are accepted by reviewers.

Security-sensitive compatibility fixtures are documented in
`docs/security/test-vectors.md` and stored in
`docs/security/test-vectors.json`. Changes to cryptographic record handling
should update those fixtures only when the compatibility impact is deliberate
and reviewed.

## Cryptographic Model

- Device identity uses Ed25519 for signatures and X25519 for key exchange.
Expand All @@ -35,6 +57,8 @@ and keeping repository metadata honest.
- Revoke access for lost, retired, or compromised devices.
- Review policy, device, and access grant changes with the same care as code
changes.
- Treat CI tokens, deploy-provider credentials, and local plaintext env files as
out-of-band secrets that need their own controls.
- Keep Ghostable updated so you receive security fixes and cryptographic model
improvements.

Expand Down
39 changes: 39 additions & 0 deletions docs/security/test-vectors.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"canonicalJSON": {
"description": "Object keys are sorted and null fields are omitted before signing.",
"expected": "{\"a\":\"first\",\"items\":[\"one\",2],\"nested\":{\"a\":7,\"b\":true},\"z\":\"last\"}",
"input": {
"a": "first",
"empty": null,
"items": [
"one",
2
],
"nested": {
"a": 7,
"b": true
},
"z": "last"
}
},
"ed25519CanonicalSignature": {
"canonical": "{\"device_id\":\"dev_fixture\",\"name\":\"fixture\",\"schema\":\"ghostable.test.v1\"}",
"publicKeyB64": "JUO5L/EJVRFHatyDadtt3JM2ZaEZeN2hQE7hBmypVZ0=",
"seedB64": "QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl8=",
"signatureB64": "d4g++eoglLHSiSgtufRVRlXK8nW/3HUtWSQhb7eWO3ckVpKoiBgbpNGEq3NfMFGA6dn49nyhLt5Qdsvprf65Bg=="
},
"hkdf": {
"encryptionKeyB64": "NCx0FwTh+ZudWBolAM0tS54H8tuWExu+znI6Af50HIo=",
"hmacKeyB64": "CLow0vzg42Z0G1DDnXzqGxg6aCIrV3czg5i3TMPMg2Q=",
"masterB64": "MDEyMzQ1Njc4OWFiY2RlZjAxMjM0NTY3ODlhYmNkZWY=",
"scope": "ghostable/project-fixture/production"
},
"version": "ghostable.security-test-vectors.v1",
"xchacha20poly1305": {
"aadB64": "eyJvcmciOiJnaG9zdGFibGUiLCJwcm9qZWN0IjoicHJvamVjdC1maXh0dXJlIiwiZW52IjoicHJvZHVjdGlvbiIsIm5hbWUiOiJBUFBfS0VZIn0=",
"ciphertextB64": "ezA1vw5FcaZL2zPPLTMsp1w5pFmT3RV88oVAnpviDHMNfrn8",
"keyB64": "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8=",
"nonceB64": "ICEiIyQlJicoKSorLC0uLzAxMjM0NTY3",
"plaintextB64": "Zml4dHVyZS1zZWNyZXQtdmFsdWU="
}
}
28 changes: 28 additions & 0 deletions docs/security/test-vectors.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Security Test Vectors

The fixture file `docs/security/test-vectors.json` contains deterministic
vectors for security-sensitive compatibility checks. These vectors are public
evidence for developers reviewing the beta security design; they are not an
external audit.

The vectors cover:

- Canonical JSON ordering and null-field omission before signing.
- HKDF-SHA256 value-key derivation for an environment scope.
- XChaCha20-Poly1305 decryption with explicit key, nonce, plaintext, and AAD.
- Ed25519 signatures over canonical Ghostable records.

The focused unit tests load this fixture and assert that the current
implementation still matches it. If a vector changes, the pull request should
explain whether the change is intentional compatibility movement, a bug fix, or
only fixture maintenance.

Run:

```sh
go test -cover ./internal/crypto ./internal/security ./internal/userpresence
make security-check
```

The fixture intentionally exercises deterministic decrypt and verify paths.
Normal value and envelope writes still use random nonces and fresh keys.
87 changes: 87 additions & 0 deletions docs/security/threat-model.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# Ghostable Threat Model

This threat model documents the current beta security design. It is not a
substitute for an external audit.

## Assets

- Plaintext environment values decrypted during local, CI, or deploy workflows.
- Local device identity material used for signatures and access grants.
- Environment keys and per-device access grants stored under `.ghostable/`.
- Signed policy, device, value, key metadata, suppression, and activity records.
- Repository history containing encrypted Ghostable state.

## Trust Boundaries

- Local machine boundary: private device identities live outside the repository
in the platform secret store when available, or in restrictive local files.
- Repository boundary: `.ghostable/` records are intended to be committed and
reviewed, but repository writers can propose policy, device, grant, and value
changes.
- Automation boundary: `GHOSTABLE_CI_TOKEN` credentials are scoped automation
secrets and are trusted only for their configured grants.
- Deploy-provider boundary: Forge, Vapor, Cloud, local `.env`, and process
injection workflows receive plaintext values after Ghostable decrypts them.

## Attacker Model

Ghostable is designed to resist:

- Passive repository readers who can inspect committed `.ghostable/` files but
do not have a valid local identity, environment key, or automation credential.
- Accidental or malicious modification of signed repository metadata, value
records, device records, access grants, and policy records.
- Stale or revoked grants after environment key rotation when the repository
state is reviewed and up to date.
- Non-interactive local use of protected production-like environments without a
scoped automation credential.

Ghostable is not designed to fully resist:

- A compromised local device that can read local identity material or decrypted
process memory.
- A compromised terminal, shell history, editor, deploy provider, CI runner, or
local plaintext `.env` file after values are decrypted.
- Reviewers accepting malicious repository changes to policy, devices, grants,
or encrypted records.
- Users placing secrets in plaintext metadata such as annotations, schema
descriptions, comments, commit messages, or issue trackers.

## Entry Points

- CLI commands that write, read, inject, deploy, or review environment values.
- `.ghostable/` record changes submitted through git.
- Local identity store reads and writes.
- Automation credentials supplied through `GHOSTABLE_CI_TOKEN`.
- Provider deploy integrations that receive decrypted values.

## Controls

- Secret values are encrypted with XChaCha20-Poly1305 using keys derived with
HKDF-SHA256 from per-environment material.
- Device identity uses Ed25519 signatures and X25519 access-grant envelopes.
- Signed records bind devices, policy, access grants, key metadata, activity,
and value payloads to the signer.
- Production-like local-device operations require interactive OS user
confirmation unless a scoped automation credential is used.
- Local plaintext cleanup, review scanning, validation, and hygiene commands
help detect operational drift but do not replace code review.

## Residual Risks

- The project has not completed an external audit.
- Local plaintext can still exist during legitimate pull, run, deploy, and
debugging workflows.
- Repository metadata is intentionally public to collaborators and can leak
names, environments, device labels, change reasons, annotations, and timing.
- Security depends on prompt revocation and key rotation after device or token
compromise.

## Review Cadence

- Run `make security-check` before security-sensitive releases.
- Review this threat model when changing cryptographic formats, access control,
local identity storage, CI token behavior, deploy integrations, or protected
environment behavior.
- Revisit the model after an external audit and after any validated security
vulnerability.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/ghostable-dev/beta

go 1.25.0
go 1.25.10

require (
github.com/chzyer/readline v1.5.1
Expand Down
Loading
Loading