Security Assurance¶
ForgeOS security is not only a set of rules. It is a set of invariants, tests, CI gates, and evidence artifacts that should prove the rules continue to hold.
What This Covers¶
The public invariants live in:
security/SECURITY_INVARIANTS.md
The public standards mapping lives in:
security/STANDARDS_CROSSWALK.md
They cover:
- production auth must not accept dev headers;
- tenant data must not cross tenant boundaries;
- Postgres RLS must block handler bugs;
- commands must stay deterministic and side-effect free except for
ctx.emit; - queries and liveQueries must be read-only;
- agent tools must inherit Forge auth, tenant, policy, telemetry, and approval boundaries;
- secret values must not appear in generated artifacts, telemetry, logs, or reports;
- webhooks must reject invalid signatures, stale timestamps, tampered bodies, and replayed event ids;
- releases must be traceable to CI and package evidence.
Security Assurance Workflow¶
The CI workflow is:
.github/workflows/security-assurance.yml
It runs:
forge generate --check
forge check --json
forge auth check --json
forge secrets check --json
forge auth prove --json
forge secrets prove --json
forge rls test --db postgres --json
forge rls mutate-test --json
forge security prove --db postgres --full --json
npm run security:evidence -- security/evidence/latest/security-proof.json security/evidence/latest
npm run release:evidence -- security/evidence/latest
npm run security:deps -- security/evidence/latest/dependency-audit.json
forge verify --strict --script-timeout-ms 120000
bun test tests/security
The current implementation covers adversarial fixtures for runtime boundaries, runtime and HTTP tenant isolation, JWT/OIDC negative auth paths, value-aware secret redaction, webhook signature/replay checks, agent tool metadata, structural agent checks, deterministic model-level agent probes, standards crosswalks, release evidence, SBOM generation, dependency vulnerability evidence, Postgres RLS tenant isolation, and RLS mutation checks.
forge security prove --json reports an assurance level:
structural-only: local checks passed, but the RLS proof did not run against Postgres.postgres-proved: the proof included the Postgres RLS adversarial probes.
By default, forge security prove aggregates structural proofs and invariant metadata. Pass --full or --run-tests to execute the invariant security tests inside the proof command and include the resulting test status in proofs.securityTests.
Alpha Surface Review¶
Recent alpha surfaces add useful agent and migration workflows, but they also expand the assurance perimeter. Treat these as explicit surfaces in release review:
| Surface | Primary risk | Required control |
|---|---|---|
| DeltaDB and agent memory | local history can imply stronger provenance than was observed | commands must label current-contract fallbacks, redact agent payloads, and mark low-confidence observation sessions as needs-review |
| CAIR query/action protocol | compact mutation plans can hide impact | mutation actions must plan before apply, write journals, and stay behind generated guard checks |
| Studio bridge | browser tooling can accidentally cross from inspect to mutate | bridge commands must keep explicit subcommands, local binding, and no secret echoing |
| Brownfield import | external manifests can overstate runtime capabilities | imports must preserve source metadata, validation diagnostics, and generated contract drift checks |
| Nuxt template and frontend bindings | generated client wiring can drift from runtime entries | CI must install the template, run Forge check, run Nuxt typecheck, and probe forge dev --once |
For release candidates, include the relevant field report or focused test output alongside normal security evidence when one of these surfaces changed.
Local Security Gate¶
Run the focused gate locally:
node ./bin/forge.mjs generate --check
node ./bin/forge.mjs check --json
node ./bin/forge.mjs auth check --json
node ./bin/forge.mjs secrets check --json
node ./bin/forge.mjs auth prove --json
node ./bin/forge.mjs secrets prove --json
node ./bin/forge.mjs ai redteam --json
node ./bin/forge.mjs ai redteam --model-level --json
node ./bin/forge.mjs rls test --db postgres --json
node ./bin/forge.mjs rls mutate-test --json
node ./bin/forge.mjs security prove --db postgres --full --json
Run the broader gate before release:
node ./bin/forge.mjs verify --strict --script-timeout-ms 120000
npm run field:test -- --package-managers npm --templates minimal-web,nuxt-web --forge-spec "npm:forgeos@alpha" --install --runtime-probes --json
npm run field:test -- --package-managers npm --templates nuxt-web --forge-spec "npm:forgeos@alpha" --install --runtime-probes --json
Evidence¶
Security evidence should be generated into:
security/evidence/latest/
Examples:
forge-check.json
auth-check.json
secrets-check.json
rls-test.json
rls-mutation.json
security-proof.json
auth-negative.json
tenant-isolation.json
runtime-boundaries.json
secret-redaction.json
agent-tools.json
webhooks.json
release-supply-chain.json
sbom.cyclonedx.json
dependency-audit.json
Evidence files must not include:
- secret values;
.envcontents;- database row data from real users;
- raw prompts when retention is disabled;
- large telemetry payloads.
Current Gaps¶
The current assurance layer is intentionally not the final security story. The next layers are:
- More runtime tenant isolation scenarios for generated agent auto-tools and liveQuery HTTP/SSE probes.
- External review of auth claim mapping, telemetry sinks, webhook recipes, and RLS policy generation.
- Broader production field reports on real Postgres deployments and longer-lived apps.
Dependency Vulnerability Evidence¶
Run:
npm run security:deps
This writes:
security/evidence/latest/dependency-audit.json
The auditor recreates temporary npm installs from the framework package, the create-app wrapper, and both template root/web manifests. Template placeholders are resolved the same way generated apps are resolved, so the evidence reflects a real npm create forgeos-app@alpha consumer path instead of raw template files.
The default threshold is high. Unwaived high or critical issues fail the command. Waivers are explicit and versioned in:
security/dependency-audit-waivers.json
Keep waivers narrow, include a reason, and set an expiration date.